blob: 0afc06ed28c6b9b4e56d8d2de94de4e71266b9e0 [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
Harald Weltec1c7e4a2021-03-02 20:47:29 +01006/* (C) 2018-2021 by Harald Welte <laforge@gnumonks.org>
Alexander Couzens6a161492020-07-12 13:45:50 +02007 * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
8 * Author: Alexander Couzens <lynxis@fe80.eu>
9 *
10 * All Rights Reserved
11 *
12 * SPDX-License-Identifier: GPL-2.0+
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28
29/* The BSS NSE only has one SGSN IP address configured, and it will use the SNS procedures
30 * to communicated its local IPs/ports as well as all the SGSN side IPs/ports and
31 * associated weights. The BSS then uses this to establish a full mesh
32 * of NSVCs between all BSS-side IPs/ports and SGSN-side IPs/ports.
33 *
34 * Known limitation/expectation/bugs:
35 * - No concurrent dual stack. It supports either IPv4 or IPv6, but not both at the same time.
36 * - SNS Add/Change/Delete: Doesn't answer on the same NSVC as received SNS ADD/CHANGE/DELETE PDUs.
37 * - SNS Add/Change/Delete: Doesn't communicated the failed IPv4/IPv6 entries on the SNS_ACK.
38 */
39
40#include <errno.h>
41
42#include <netinet/in.h>
43#include <arpa/inet.h>
44#include <stdint.h>
45
46#include <osmocom/core/fsm.h>
47#include <osmocom/core/msgb.h>
48#include <osmocom/core/socket.h>
Alexander Couzens412bc342020-11-19 05:24:37 +010049#include <osmocom/core/sockaddr_str.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020050#include <osmocom/gsm/tlv.h>
51#include <osmocom/gprs/gprs_msgb.h>
52#include <osmocom/gprs/gprs_ns2.h>
53#include <osmocom/gprs/protocol/gsm_08_16.h>
54
55#include "gprs_ns2_internal.h"
56
57#define S(x) (1 << (x))
58
Harald Welte4f127462021-03-02 20:49:10 +010059enum ns2_sns_role {
60 GPRS_SNS_ROLE_BSS,
61 GPRS_SNS_ROLE_SGSN,
62};
63
Harald Welte694dad52021-03-23 15:22:16 +010064/* BSS-side-only states _ST_BSS_; SGSN-side only states _ST_SGSN_; others shared */
Alexander Couzens6a161492020-07-12 13:45:50 +020065enum gprs_sns_bss_state {
66 GPRS_SNS_ST_UNCONFIGURED,
Harald Welte694dad52021-03-23 15:22:16 +010067 GPRS_SNS_ST_BSS_SIZE, /*!< SNS-SIZE procedure ongoing */
68 GPRS_SNS_ST_BSS_CONFIG_BSS, /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */
69 GPRS_SNS_ST_BSS_CONFIG_SGSN, /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */
Alexander Couzens6a161492020-07-12 13:45:50 +020070 GPRS_SNS_ST_CONFIGURED,
Harald Welte4f127462021-03-02 20:49:10 +010071 GPRS_SNS_ST_SGSN_WAIT_CONFIG, /* !< SGSN role: Wait for CONFIG from BSS */
72 GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, /* !< SGSN role: Wait for CONFIG-ACK from BSS */
Alexander Couzens1f3193d2021-06-05 22:08:11 +020073 GPRS_SNS_ST_LOCAL_PROCEDURE, /*!< in process of a ADD/DEL/CHANGE procedure towards SGSN (BSS->SGSN) */
Alexander Couzens6a161492020-07-12 13:45:50 +020074};
75
Alexander Couzens6a161492020-07-12 13:45:50 +020076static const struct value_string gprs_sns_event_names[] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +020077 { NS2_SNS_EV_REQ_SELECT_ENDPOINT, "REQ_SELECT_ENDPOINT" },
78 { NS2_SNS_EV_RX_SIZE, "RX_SIZE" },
79 { NS2_SNS_EV_RX_SIZE_ACK, "RX_SIZE_ACK" },
80 { NS2_SNS_EV_RX_CONFIG, "RX_CONFIG" },
81 { NS2_SNS_EV_RX_CONFIG_END, "RX_CONFIG_END" },
82 { NS2_SNS_EV_RX_CONFIG_ACK, "RX_CONFIG_ACK" },
83 { NS2_SNS_EV_RX_ADD, "RX_ADD" },
84 { NS2_SNS_EV_RX_DELETE, "RX_DELETE" },
85 { NS2_SNS_EV_RX_ACK, "RX_ACK" },
86 { NS2_SNS_EV_RX_CHANGE_WEIGHT, "RX_CHANGE_WEIGHT" },
87 { NS2_SNS_EV_REQ_NO_NSVC, "REQ_NO_NSVC" },
Alexander Couzens83f06ce2021-08-06 19:50:09 +020088 { NS2_SNS_EV_REQ_FREE_NSVCS, "REQ_FREE_NSVCS" },
Alexander Couzens175eb7b2021-07-20 18:41:14 +020089 { NS2_SNS_EV_REQ_NSVC_ALIVE, "REQ_NSVC_ALIVE"},
90 { NS2_SNS_EV_REQ_ADD_BIND, "REQ_ADD_BIND"},
91 { NS2_SNS_EV_REQ_DELETE_BIND, "REQ_DELETE_BIND"},
Alexander Couzens1f3193d2021-06-05 22:08:11 +020092 { NS2_SNS_EV_REQ_CHANGE_WEIGHT, "REQ_CHANGE_WEIGHT"},
Alexander Couzens6a161492020-07-12 13:45:50 +020093 { 0, NULL }
94};
95
Alexander Couzens9cd39ac2021-06-06 18:57:56 +020096#define GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER (void *) 1
97
Alexander Couzens1f3193d2021-06-05 22:08:11 +020098enum sns_procedure {
99 SNS_PROC_NONE, /*!< used as invalid/idle value */
100 SNS_PROC_ADD,
101 SNS_PROC_DEL,
102 SNS_PROC_CHANGE_WEIGHT,
103};
104
Alexander Couzense769f522020-12-07 07:37:07 +0100105struct sns_endpoint {
106 struct llist_head list;
107 struct osmo_sockaddr saddr;
108};
109
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100110struct ns2_sns_bind {
111 struct llist_head list;
112 struct gprs_ns2_vc_bind *bind;
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200113 uint8_t change_weight_state;
114};
115
116struct ns2_sns_procedure {
117 struct llist_head list;
118 struct ns2_sns_bind *sbind;
119 uint16_t sig_weight;
120 uint16_t data_weight;
121 /* copy entry to protect against changes of gss->local */
122 struct gprs_ns_ie_ip4_elem ip4;
123 struct gprs_ns_ie_ip6_elem ip6;
124 enum sns_procedure procedure;
125 uint8_t trans_id;
126 /* is the procedure in process */
127 bool running;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100128};
129
Alexander Couzens71128672021-06-05 18:44:01 +0200130struct ns2_sns_elems {
131 struct gprs_ns_ie_ip4_elem *ip4;
132 unsigned int num_ip4;
133 struct gprs_ns_ie_ip6_elem *ip6;
134 unsigned int num_ip6;
135};
136
Alexander Couzens6a161492020-07-12 13:45:50 +0200137struct ns2_sns_state {
138 struct gprs_ns2_nse *nse;
139
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200140 /* containing the address family AF_* */
141 int family;
Harald Welte4f127462021-03-02 20:49:10 +0100142 enum ns2_sns_role role; /* local role: BSS or SGSN */
Alexander Couzens6a161492020-07-12 13:45:50 +0200143
Alexander Couzense769f522020-12-07 07:37:07 +0100144 /* holds the list of initial SNS endpoints */
145 struct llist_head sns_endpoints;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100146 /* list of used struct ns2_sns_bind */
147 struct llist_head binds;
148 /* pointer to the bind which was used to initiate the SNS connection */
149 struct ns2_sns_bind *initial_bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100150 /* prevent recursive reselection */
151 bool reselection_running;
152
Alexander Couzensdb07a442021-06-06 18:58:01 +0200153 /* protection against recursive free() */
154 bool block_no_nsvc_events;
155
Alexander Couzense769f522020-12-07 07:37:07 +0100156 /* The current initial SNS endpoints.
157 * The initial connection will be moved into the NSE
158 * if configured via SNS. Otherwise it will be removed
159 * in configured state. */
160 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200161 /* all SNS PDU will be sent over this nsvc */
162 struct gprs_ns2_vc *sns_nsvc;
Alexander Couzens90ee9632020-12-07 06:18:32 +0100163 /* timer N */
164 int N;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100165 /* true if at least one nsvc is alive */
166 bool alive;
Alexander Couzens6a161492020-07-12 13:45:50 +0200167
168 /* local configuration to send to the remote end */
Alexander Couzens71128672021-06-05 18:44:01 +0200169 struct ns2_sns_elems local;
Alexander Couzens6a161492020-07-12 13:45:50 +0200170
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200171 /* local configuration after all local procedures applied */
172 struct ns2_sns_elems local_procedure;
173
Alexander Couzens71128672021-06-05 18:44:01 +0200174 /* remote configuration as received */
175 struct ns2_sns_elems remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200176
177 /* local configuration about our capabilities in terms of connections to
178 * remote (SGSN) side */
179 size_t num_max_nsvcs;
180 size_t num_max_ip4_remote;
181 size_t num_max_ip6_remote;
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200182
183 struct llist_head procedures;
184 struct ns2_sns_procedure *current_procedure;
185 uint8_t trans_id;
Alexander Couzens6a161492020-07-12 13:45:50 +0200186};
187
188static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
189{
190 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
191 return gss->nse;
192}
193
Alexander Couzens652ab4d2021-06-12 23:09:46 +0200194/* The SNS has failed. Etither restart the SNS (BSS) or remove the SNS (SGSN) */
195#define sns_failed(fi, reason) \
196 _sns_failed(fi, reason, __FILE__, __LINE__)
197static void _sns_failed(struct osmo_fsm_inst *fi, const char *reason, const char *file, int line)
198{
199 struct ns2_sns_state *gss = fi->priv;
200
201 if (reason)
Alexander Couzensb0874cd2021-07-20 22:15:00 +0200202 LOGPFSMLSRC(fi, LOGL_ERROR, file, line, "NSE %d: SNS failed: %s\n", gss->nse->nsei, reason);
Alexander Couzens652ab4d2021-06-12 23:09:46 +0200203
Alexander Couzens1adfd232021-07-20 22:16:09 +0200204 gss->alive = false;
Alexander Couzens652ab4d2021-06-12 23:09:46 +0200205 if (gss->role == GPRS_SNS_ROLE_SGSN) {
206 if (!gss->nse->persistent)
207 gprs_ns2_free_nse(gss->nse);
208 else
209 _osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0, file, line);
210 } else {
Alexander Couzens175eb7b2021-07-20 18:41:14 +0200211 _osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL, file, line);
Alexander Couzens652ab4d2021-06-12 23:09:46 +0200212 }
213}
214
Alexander Couzens6a161492020-07-12 13:45:50 +0200215/* helper function to compute the sum of all (data or signaling) weights */
Alexander Couzens62310552021-06-06 02:43:14 +0200216static int ip4_weight_sum(const struct ns2_sns_elems *elems, bool data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200217{
218 unsigned int i;
219 int weight_sum = 0;
220
Alexander Couzens62310552021-06-06 02:43:14 +0200221 for (i = 0; i < elems->num_ip4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200222 if (data_weight)
Alexander Couzens62310552021-06-06 02:43:14 +0200223 weight_sum += elems->ip4[i].data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200224 else
Alexander Couzens62310552021-06-06 02:43:14 +0200225 weight_sum += elems->ip4[i].sig_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200226 }
227 return weight_sum;
228}
Alexander Couzens62310552021-06-06 02:43:14 +0200229#define ip4_weight_sum_data(elems) ip4_weight_sum(elems, true)
230#define ip4_weight_sum_sig(elems) ip4_weight_sum(elems, false)
Alexander Couzens6a161492020-07-12 13:45:50 +0200231
232/* helper function to compute the sum of all (data or signaling) weights */
Alexander Couzens62310552021-06-06 02:43:14 +0200233static int ip6_weight_sum(const struct ns2_sns_elems *elems, bool data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200234{
235 unsigned int i;
236 int weight_sum = 0;
237
Alexander Couzens62310552021-06-06 02:43:14 +0200238 for (i = 0; i < elems->num_ip6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200239 if (data_weight)
Alexander Couzens62310552021-06-06 02:43:14 +0200240 weight_sum += elems->ip6[i].data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200241 else
Alexander Couzens62310552021-06-06 02:43:14 +0200242 weight_sum += elems->ip6[i].sig_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200243 }
244 return weight_sum;
245}
Alexander Couzens62310552021-06-06 02:43:14 +0200246#define ip6_weight_sum_data(elems) ip6_weight_sum(elems, true)
247#define ip6_weight_sum_sig(elems) ip6_weight_sum(elems, false)
Alexander Couzens6a161492020-07-12 13:45:50 +0200248
Alexander Couzens019da4b2021-06-06 02:48:18 +0200249static int ip46_weight_sum(const struct ns2_sns_elems *elems, bool data_weight)
Harald Weltec1c7e4a2021-03-02 20:47:29 +0100250{
Alexander Couzens019da4b2021-06-06 02:48:18 +0200251 return ip4_weight_sum(elems, data_weight) +
252 ip6_weight_sum(elems, data_weight);
Harald Weltec1c7e4a2021-03-02 20:47:29 +0100253}
Alexander Couzens019da4b2021-06-06 02:48:18 +0200254#define ip46_weight_sum_data(elems) ip46_weight_sum(elems, true)
255#define ip46_weight_sum_sig(elems) ip46_weight_sum(elems, false)
Harald Weltec1c7e4a2021-03-02 20:47:29 +0100256
Alexander Couzens6a161492020-07-12 13:45:50 +0200257static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
258 const struct gprs_ns_ie_ip4_elem *ip4)
259{
260 struct osmo_sockaddr sa;
261 /* copy over. Both data structures use network byte order */
262 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
263 sa.u.sin.sin_port = ip4->udp_port;
264 sa.u.sin.sin_family = AF_INET;
265
Alexander Couzens38b19e82020-09-23 23:56:37 +0200266 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200267}
268
269static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
270 const struct gprs_ns_ie_ip6_elem *ip6)
271{
272 struct osmo_sockaddr sa;
273 /* copy over. Both data structures use network byte order */
274 sa.u.sin6.sin6_addr = ip6->ip_addr;
275 sa.u.sin6.sin6_port = ip6->udp_port;
276 sa.u.sin6.sin6_family = AF_INET;
277
Alexander Couzens38b19e82020-09-23 23:56:37 +0200278 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200279}
280
Alexander Couzens125298f2020-10-11 21:22:42 +0200281/*! Return the initial SNS remote socket address
282 * \param nse NS Entity
283 * \return address of the initial SNS connection; NULL in case of error
284 */
285const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
286{
287 struct ns2_sns_state *gss;
288
289 if (!nse->bss_sns_fi)
290 return NULL;
291
292 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100293 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200294}
295
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100296/*! called when a nsvc is beeing freed or the nsvc became dead */
297void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200298{
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100299 struct gprs_ns2_nse *nse = nsvc->nse;
Alexander Couzens6a161492020-07-12 13:45:50 +0200300 struct gprs_ns2_vc *tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100301 struct osmo_fsm_inst *fi = nse->bss_sns_fi;
Alexander Couzens6a161492020-07-12 13:45:50 +0200302 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +0200303
304 if (!fi)
305 return;
306
307 gss = (struct ns2_sns_state *) fi->priv;
308 if (nsvc != gss->sns_nsvc)
309 return;
310
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100311 gss->sns_nsvc = NULL;
312 if (gss->alive) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200313 llist_for_each_entry(tmp, &nse->nsvc, list) {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100314 if (ns2_vc_is_unblocked(tmp)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200315 gss->sns_nsvc = tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100316 return;
317 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200318 }
319 } else {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100320 /* the SNS is waiting for its first NS-VC to come up
321 * choose any other nsvc */
322 llist_for_each_entry(tmp, &nse->nsvc, list) {
323 if (nsvc != tmp) {
324 gss->sns_nsvc = tmp;
325 return;
326 }
327 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200328 }
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100329
Alexander Couzensdb07a442021-06-06 18:58:01 +0200330 if (gss->block_no_nsvc_events)
331 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_NO_NSVC, NULL);
Alexander Couzens6a161492020-07-12 13:45:50 +0200332}
333
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200334static void ns2_clear_elems(struct ns2_sns_elems *elems)
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100335{
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200336 TALLOC_FREE(elems->ip4);
337 TALLOC_FREE(elems->ip6);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100338
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200339 elems->num_ip4 = 0;
340 elems->num_ip6 = 0;
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100341}
342
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200343static void ns2_clear_procedures(struct ns2_sns_state *gss)
344{
345 struct ns2_sns_procedure *procedure, *tmp;
346 gss->current_procedure = NULL;
347 llist_for_each_entry_safe(procedure, tmp, &gss->procedures, list) {
348 llist_del(&procedure->list);
349 talloc_free(procedure);
350 }
351}
352
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100353static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
354 uint8_t sig_weight, uint8_t data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200355{
356 struct gprs_ns2_inst *nsi = nse->nsi;
357 struct gprs_ns2_vc *nsvc;
358 struct gprs_ns2_vc_bind *bind;
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100359
360 /* for every bind, create a connection if bind type == IP */
361 llist_for_each_entry(bind, &nsi->binding, list) {
362 if (bind->ll != GPRS_NS2_LL_UDP)
363 continue;
364 /* ignore failed connection */
365 nsvc = gprs_ns2_ip_connect_inactive(bind,
366 remote,
367 nse, 0);
368 if (!nsvc) {
369 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
370 continue;
371 }
372
373 nsvc->sig_weight = sig_weight;
374 nsvc->data_weight = data_weight;
375 }
376}
377
378static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
379 struct gprs_ns2_nse *nse,
380 const struct gprs_ns_ie_ip4_elem *ip4)
381{
Alexander Couzensc068d862020-10-12 04:11:51 +0200382 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200383 /* copy over. Both data structures use network byte order */
384 remote.u.sin.sin_family = AF_INET;
385 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
386 remote.u.sin.sin_port = ip4->udp_port;
387
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100388 ns2_vc_create_ip(fi, nse, &remote, ip4->sig_weight, ip4->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200389}
390
391static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
392 struct gprs_ns2_nse *nse,
393 const struct gprs_ns_ie_ip6_elem *ip6)
394{
Alexander Couzens6a161492020-07-12 13:45:50 +0200395 struct osmo_sockaddr remote = {};
396 /* copy over. Both data structures use network byte order */
397 remote.u.sin6.sin6_family = AF_INET6;
398 remote.u.sin6.sin6_addr = ip6->ip_addr;
399 remote.u.sin6.sin6_port = ip6->udp_port;
400
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100401 ns2_vc_create_ip(fi, nse, &remote, ip6->sig_weight, ip6->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200402}
403
Harald Weltee8c61062021-03-24 13:16:27 +0100404static struct gprs_ns2_vc *nsvc_for_bind_and_remote(struct gprs_ns2_nse *nse,
405 struct gprs_ns2_vc_bind *bind,
406 const struct osmo_sockaddr *remote)
407{
408 struct gprs_ns2_vc *nsvc;
409
410 llist_for_each_entry(nsvc, &nse->nsvc, list) {
411 if (nsvc->bind != bind)
412 continue;
413
414 if (!osmo_sockaddr_cmp(remote, gprs_ns2_ip_vc_remote(nsvc)))
415 return nsvc;
416 }
417 return NULL;
418}
Alexander Couzens6a161492020-07-12 13:45:50 +0200419
420static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
421{
422 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
423 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
424 struct gprs_ns2_vc *nsvc;
Harald Welte3053bbb2021-03-24 13:22:18 +0100425 struct ns2_sns_bind *sbind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200426 struct osmo_sockaddr remote = { };
427 unsigned int i;
428
Harald Weltee8c61062021-03-24 13:16:27 +0100429 /* iterate over all remote IPv4 endpoints */
Alexander Couzens71128672021-06-05 18:44:01 +0200430 for (i = 0; i < gss->remote.num_ip4; i++) {
431 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->remote.ip4[i];
Alexander Couzens6a161492020-07-12 13:45:50 +0200432
433 remote.u.sin.sin_family = AF_INET;
434 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
435 remote.u.sin.sin_port = ip4->udp_port;
436
Harald Welte3053bbb2021-03-24 13:22:18 +0100437 /* iterate over all local binds within this SNS */
438 llist_for_each_entry(sbind, &gss->binds, list) {
439 struct gprs_ns2_vc_bind *bind = sbind->bind;
440
Harald Weltee8c61062021-03-24 13:16:27 +0100441 /* we only care about UDP binds */
Daniel Willmann967e2c12021-01-14 16:58:17 +0100442 if (bind->ll != GPRS_NS2_LL_UDP)
443 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200444
Harald Weltee8c61062021-03-24 13:16:27 +0100445 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
446 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200447 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
448 if (!nsvc) {
449 /* TODO: add to a list to send back a NS-STATUS */
450 continue;
451 }
452 }
453
454 /* update data / signalling weight */
455 nsvc->data_weight = ip4->data_weight;
456 nsvc->sig_weight = ip4->sig_weight;
457 nsvc->sns_only = false;
458 }
459 }
460
Harald Weltee8c61062021-03-24 13:16:27 +0100461 /* iterate over all remote IPv4 endpoints */
Alexander Couzens71128672021-06-05 18:44:01 +0200462 for (i = 0; i < gss->remote.num_ip6; i++) {
463 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->remote.ip6[i];
Alexander Couzens6a161492020-07-12 13:45:50 +0200464
465 remote.u.sin6.sin6_family = AF_INET6;
466 remote.u.sin6.sin6_addr = ip6->ip_addr;
467 remote.u.sin6.sin6_port = ip6->udp_port;
468
Harald Welte3053bbb2021-03-24 13:22:18 +0100469 /* iterate over all local binds within this SNS */
470 llist_for_each_entry(sbind, &gss->binds, list) {
471 struct gprs_ns2_vc_bind *bind = sbind->bind;
472
Daniel Willmann967e2c12021-01-14 16:58:17 +0100473 if (bind->ll != GPRS_NS2_LL_UDP)
474 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200475
Harald Weltee8c61062021-03-24 13:16:27 +0100476 /* we only care about UDP binds */
477 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
478 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200479 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
480 if (!nsvc) {
481 /* TODO: add to a list to send back a NS-STATUS */
482 continue;
483 }
484 }
485
486 /* update data / signalling weight */
487 nsvc->data_weight = ip6->data_weight;
488 nsvc->sig_weight = ip6->sig_weight;
489 nsvc->sns_only = false;
490 }
491 }
492
493
494 return 0;
495}
496
497/* Add a given remote IPv4 element to gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200498static int add_ip4_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
499 const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +0200500{
Alexander Couzens6a161492020-07-12 13:45:50 +0200501 /* check for duplicates */
Alexander Couzenscc56ddc2021-06-06 03:33:35 +0200502 for (unsigned int i = 0; i < elems->num_ip4; i++) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200503 if (memcmp(&elems->ip4[i], ip4, sizeof(*ip4)))
Alexander Couzens6a161492020-07-12 13:45:50 +0200504 continue;
Alexander Couzensd3507e82021-06-06 03:32:32 +0200505 return -1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200506 }
507
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200508 elems->ip4 = talloc_realloc(gss, elems->ip4, struct gprs_ns_ie_ip4_elem,
509 elems->num_ip4+1);
510 elems->ip4[elems->num_ip4] = *ip4;
511 elems->num_ip4 += 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200512 return 0;
513}
514
515/* Remove a given remote IPv4 element from gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200516static int remove_ip4_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
517 const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +0200518{
519 unsigned int i;
520
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200521 for (i = 0; i < elems->num_ip4; i++) {
522 if (memcmp(&elems->ip4[i], ip4, sizeof(*ip4)))
Alexander Couzens6a161492020-07-12 13:45:50 +0200523 continue;
524 /* all array elements < i remain as they are; all > i are shifted left by one */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200525 memmove(&elems->ip4[i], &elems->ip4[i+1], elems->num_ip4-i-1);
526 elems->num_ip4 -= 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200527 return 0;
528 }
529 return -1;
530}
531
532/* update the weights for specified remote IPv4 */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200533static int update_ip4_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
534 const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +0200535{
536 unsigned int i;
537
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200538 for (i = 0; i < elems->num_ip4; i++) {
539 if (elems->ip4[i].ip_addr != ip4->ip_addr ||
540 elems->ip4[i].udp_port != ip4->udp_port)
Alexander Couzens6a161492020-07-12 13:45:50 +0200541 continue;
542
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200543 elems->ip4[i].sig_weight = ip4->sig_weight;
544 elems->ip4[i].data_weight = ip4->data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200545 return 0;
546 }
547 return -1;
548}
549
550/* Add a given remote IPv6 element to gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200551static int add_ip6_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
552 const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +0200553{
Alexander Couzenscc56ddc2021-06-06 03:33:35 +0200554 /* check for duplicates */
555 for (unsigned int i = 0; i < elems->num_ip6; i++) {
556 if (memcmp(&elems->ip6[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
557 elems->ip6[i].udp_port != ip6->udp_port)
558 continue;
559 return -1;
560 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200561
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200562 elems->ip6 = talloc_realloc(gss, elems->ip6, struct gprs_ns_ie_ip6_elem,
563 elems->num_ip6+1);
564 elems->ip6[elems->num_ip6] = *ip6;
565 elems->num_ip6 += 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200566 return 0;
567}
568
569/* Remove a given remote IPv6 element from gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200570static int remove_ip6_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
571 const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +0200572{
573 unsigned int i;
574
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200575 for (i = 0; i < elems->num_ip6; i++) {
576 if (memcmp(&elems->ip6[i], ip6, sizeof(*ip6)))
Alexander Couzens6a161492020-07-12 13:45:50 +0200577 continue;
578 /* all array elements < i remain as they are; all > i are shifted left by one */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200579 memmove(&elems->ip6[i], &elems->ip6[i+1], elems->num_ip6-i-1);
580 elems->num_ip6 -= 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200581 return 0;
582 }
583 return -1;
584}
585
586/* update the weights for specified remote IPv6 */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200587static int update_ip6_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
588 const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +0200589{
590 unsigned int i;
591
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200592 for (i = 0; i < elems->num_ip6; i++) {
593 if (memcmp(&elems->ip6[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
594 elems->ip6[i].udp_port != ip6->udp_port)
Alexander Couzens6a161492020-07-12 13:45:50 +0200595 continue;
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200596 elems->ip6[i].sig_weight = ip6->sig_weight;
597 elems->ip6[i].data_weight = ip6->data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200598 return 0;
599 }
600 return -1;
601}
602
Alexander Couzensdb07a442021-06-06 18:58:01 +0200603static int remove_bind_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems, struct ns2_sns_bind *sbind)
604{
605 struct gprs_ns_ie_ip4_elem ip4;
606 struct gprs_ns_ie_ip6_elem ip6;
607 const struct osmo_sockaddr *saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
608
609 switch (saddr->u.sa.sa_family) {
610 case AF_INET:
611 ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
612 ip4.udp_port = saddr->u.sin.sin_port;
613 ip4.sig_weight = sbind->bind->sns_sig_weight;
614 ip4.data_weight = sbind->bind->sns_data_weight;
615 return remove_ip4_elem(gss, elems, &ip4);
616 case AF_INET6:
617 memcpy(&ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));
618 ip6.udp_port = saddr->u.sin.sin_port;
619 ip6.sig_weight = sbind->bind->sns_sig_weight;
620 ip6.data_weight = sbind->bind->sns_data_weight;
621 return remove_ip6_elem(gss, elems, &ip6);
622 default:
623 return -1;
624 }
625
626 return -1;
627}
628
Alexander Couzens6a161492020-07-12 13:45:50 +0200629static 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)
630{
631 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
632 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
633 struct gprs_ns2_vc *nsvc;
634 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200635 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200636 uint8_t new_signal;
637 uint8_t new_data;
638
639 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
640 * signalling weights of all the peer IP endpoints configured for this NSE is
641 * equal to zero or if the resulting sum of the data weights of all the peer IP
642 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
643 * SNS-ACK PDU with a cause code of "Invalid weights". */
644
645 if (ip4) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200646 if (update_ip4_elem(gss, &gss->remote, ip4))
Alexander Couzens6a161492020-07-12 13:45:50 +0200647 return -NS_CAUSE_UNKN_IP_EP;
648
649 /* copy over. Both data structures use network byte order */
650 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
651 sa.u.sin.sin_port = ip4->udp_port;
652 sa.u.sin.sin_family = AF_INET;
653 new_signal = ip4->sig_weight;
654 new_data = ip4->data_weight;
655 } else if (ip6) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200656 if (update_ip6_elem(gss, &gss->remote, ip6))
Alexander Couzens6a161492020-07-12 13:45:50 +0200657 return -NS_CAUSE_UNKN_IP_EP;
658
659 /* copy over. Both data structures use network byte order */
660 sa.u.sin6.sin6_addr = ip6->ip_addr;
661 sa.u.sin6.sin6_port = ip6->udp_port;
662 sa.u.sin6.sin6_family = AF_INET6;
663 new_signal = ip6->sig_weight;
664 new_data = ip6->data_weight;
665 } else {
666 OSMO_ASSERT(false);
667 }
668
669 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200670 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200671 /* all nsvc in NSE should be IP/UDP nsvc */
672 OSMO_ASSERT(remote);
673
674 if (osmo_sockaddr_cmp(&sa, remote))
675 continue;
676
677 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
678 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
679 nsvc->sig_weight, new_signal);
680
681 nsvc->data_weight = new_data;
682 nsvc->sig_weight = new_signal;
683 }
684
685 return 0;
686}
687
688static int do_sns_delete(struct osmo_fsm_inst *fi,
689 const struct gprs_ns_ie_ip4_elem *ip4,
690 const struct gprs_ns_ie_ip6_elem *ip6)
691{
692 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
693 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
694 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200695 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200696 struct osmo_sockaddr sa = {};
697
698 if (ip4) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200699 if (remove_ip4_elem(gss, &gss->remote, ip4) < 0)
Alexander Couzens6a161492020-07-12 13:45:50 +0200700 return -NS_CAUSE_UNKN_IP_EP;
701 /* copy over. Both data structures use network byte order */
702 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
703 sa.u.sin.sin_port = ip4->udp_port;
704 sa.u.sin.sin_family = AF_INET;
705 } else if (ip6) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200706 if (remove_ip6_elem(gss, &gss->remote, ip6))
Alexander Couzens6a161492020-07-12 13:45:50 +0200707 return -NS_CAUSE_UNKN_IP_EP;
708
709 /* copy over. Both data structures use network byte order */
710 sa.u.sin6.sin6_addr = ip6->ip_addr;
711 sa.u.sin6.sin6_port = ip6->udp_port;
712 sa.u.sin6.sin6_family = AF_INET6;
713 } else {
714 OSMO_ASSERT(false);
715 }
716
717 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200718 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200719 /* all nsvc in NSE should be IP/UDP nsvc */
720 OSMO_ASSERT(remote);
721 if (osmo_sockaddr_cmp(&sa, remote))
722 continue;
723
724 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
725 gprs_ns2_free_nsvc(nsvc);
726 }
727
728 return 0;
729}
730
731static int do_sns_add(struct osmo_fsm_inst *fi,
732 const struct gprs_ns_ie_ip4_elem *ip4,
733 const struct gprs_ns_ie_ip6_elem *ip6)
734{
735 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
736 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
737 struct gprs_ns2_vc *nsvc;
738 int rc = 0;
739
740 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
741 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
742 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200743 switch (gss->family) {
744 case AF_INET:
Alexander Couzensd3507e82021-06-06 03:32:32 +0200745 if (gss->remote.num_ip4 >= gss->num_max_ip4_remote)
746 return -NS_CAUSE_INVAL_NR_NS_VC;
747 /* TODO: log message duplicate */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200748 rc = add_ip4_elem(gss, &gss->remote, ip4);
Alexander Couzens6a161492020-07-12 13:45:50 +0200749 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200750 case AF_INET6:
Alexander Couzensd3507e82021-06-06 03:32:32 +0200751 if (gss->remote.num_ip6 >= gss->num_max_ip6_remote)
752 return -NS_CAUSE_INVAL_NR_NS_VC;
753 /* TODO: log message duplicate */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200754 rc = add_ip6_elem(gss, &gss->remote, ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +0200755 break;
756 default:
757 /* the gss->ip is initialized with the bss */
758 OSMO_ASSERT(false);
759 }
760
761 if (rc)
Alexander Couzensd3507e82021-06-06 03:32:32 +0200762 return -NS_CAUSE_PROTO_ERR_UNSPEC;
Alexander Couzens6a161492020-07-12 13:45:50 +0200763
764 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
765 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
766 * unspecified" */
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200767 switch (gss->family) {
768 case AF_INET:
Alexander Couzens6a161492020-07-12 13:45:50 +0200769 nsvc = nsvc_by_ip4_elem(nse, ip4);
770 if (nsvc) {
771 /* the nsvc should be already in sync with the ip4 / ip6 elements */
772 return -NS_CAUSE_PROTO_ERR_UNSPEC;
773 }
774
775 /* TODO: failure case */
776 ns2_nsvc_create_ip4(fi, nse, ip4);
777 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200778 case AF_INET6:
Alexander Couzens6a161492020-07-12 13:45:50 +0200779 nsvc = nsvc_by_ip6_elem(nse, ip6);
780 if (nsvc) {
781 /* the nsvc should be already in sync with the ip4 / ip6 elements */
782 return -NS_CAUSE_PROTO_ERR_UNSPEC;
783 }
784
785 /* TODO: failure case */
786 ns2_nsvc_create_ip6(fi, nse, ip6);
787 break;
788 }
789
790 gprs_ns2_start_alive_all_nsvcs(nse);
791
792 return 0;
793}
794
795
Harald Welte694dad52021-03-23 15:22:16 +0100796static void ns2_sns_st_bss_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +0200797{
Harald Weltef61a9152021-03-02 22:20:17 +0100798 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
799 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
Alexander Couzense769f522020-12-07 07:37:07 +0100800 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200801}
802
Harald Welte694dad52021-03-23 15:22:16 +0100803static void ns2_sns_st_bss_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +0200804{
Harald Weltef61a9152021-03-02 22:20:17 +0100805 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +0200806 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
807 struct gprs_ns2_inst *nsi = nse->nsi;
808 struct tlv_parsed *tp = NULL;
809
Harald Weltef61a9152021-03-02 22:20:17 +0100810 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
811
Alexander Couzens6a161492020-07-12 13:45:50 +0200812 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +0200813 case NS2_SNS_EV_RX_SIZE_ACK:
Alexander Couzens6a161492020-07-12 13:45:50 +0200814 tp = data;
815 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
816 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
817 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
818 /* TODO: What to do? */
819 } else {
Harald Welte694dad52021-03-23 15:22:16 +0100820 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_BSS,
Alexander Couzens6a161492020-07-12 13:45:50 +0200821 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
822 }
823 break;
824 default:
825 OSMO_ASSERT(0);
826 }
827}
828
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200829static int ns2_sns_count_num_local_ep(struct osmo_fsm_inst *fi, int ip_proto)
Harald Welte01fa6a32021-03-04 19:49:38 +0100830{
831 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
832 struct ns2_sns_bind *sbind;
833 int count = 0;
834
835 llist_for_each_entry(sbind, &gss->binds, list) {
836 const struct osmo_sockaddr *sa = gprs_ns2_ip_bind_sockaddr(sbind->bind);
837 if (!sa)
838 continue;
839
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200840 switch (ip_proto) {
841 case AF_INET:
Harald Welte01fa6a32021-03-04 19:49:38 +0100842 if (sa->u.sas.ss_family == AF_INET)
843 count++;
844 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200845 case AF_INET6:
Harald Welte01fa6a32021-03-04 19:49:38 +0100846 if (sa->u.sas.ss_family == AF_INET6)
847 count++;
848 break;
849 }
850 }
851 return count;
852}
853
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200854static int ns2_sns_copy_local_endpoints(struct ns2_sns_state *gss)
855{
856 switch (gss->family) {
857 case AF_INET:
858 gss->local_procedure.ip4 = talloc_realloc(gss, gss->local_procedure.ip4, struct gprs_ns_ie_ip4_elem,
859 gss->local.num_ip4);
860 if (!gss->local_procedure.ip4)
861 return -ENOMEM;
862
863 gss->local_procedure.num_ip4 = gss->local.num_ip4;
864 memcpy(gss->local_procedure.ip4, gss->local.ip4,
865 sizeof(struct gprs_ns_ie_ip4_elem) * gss->local.num_ip4);
866 break;
867 case AF_INET6:
868 gss->local_procedure.ip6 = talloc_realloc(gss, gss->local_procedure.ip6, struct gprs_ns_ie_ip6_elem,
869 gss->local.num_ip6);
870 if (!gss->local_procedure.ip6)
871 return -ENOMEM;
872
873 gss->local_procedure.num_ip6 = gss->local.num_ip6;
874 memcpy(gss->local_procedure.ip6, gss->local.ip6,
875 sizeof(struct gprs_ns_ie_ip6_elem) * gss->local.num_ip6);
876 break;
877 default:
878 OSMO_ASSERT(0);
879 }
880
881 return 0;
882}
883
Harald Welte24920e22021-03-04 13:03:27 +0100884static void ns2_sns_compute_local_ep_from_binds(struct osmo_fsm_inst *fi)
Alexander Couzens6a161492020-07-12 13:45:50 +0200885{
886 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100887 struct gprs_ns_ie_ip4_elem *ip4_elems;
888 struct gprs_ns_ie_ip6_elem *ip6_elems;
889 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100890 struct ns2_sns_bind *sbind;
Harald Welte4f127462021-03-02 20:49:10 +0100891 const struct osmo_sockaddr *remote;
Alexander Couzense769f522020-12-07 07:37:07 +0100892 const struct osmo_sockaddr *sa;
893 struct osmo_sockaddr local;
894 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200895
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200896 ns2_clear_elems(&gss->local);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100897
Alexander Couzense769f522020-12-07 07:37:07 +0100898 /* no initial available */
Harald Welte4f127462021-03-02 20:49:10 +0100899 if (gss->role == GPRS_SNS_ROLE_BSS) {
900 if (!gss->initial)
901 return;
902 remote = &gss->initial->saddr;
903 } else
904 remote = gprs_ns2_ip_vc_remote(gss->sns_nsvc);
Alexander Couzense769f522020-12-07 07:37:07 +0100905
906 /* count how many bindings are available (only UDP binds) */
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100907 count = llist_count(&gss->binds);
Alexander Couzense769f522020-12-07 07:37:07 +0100908 if (count == 0) {
Harald Welte05992872021-03-04 15:49:21 +0100909 LOGPFSML(fi, LOGL_ERROR, "No local binds for this NSE -> cannot determine IP endpoints\n");
Alexander Couzense769f522020-12-07 07:37:07 +0100910 return;
911 }
912
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200913 switch (gss->family) {
914 case AF_INET:
Alexander Couzens71128672021-06-05 18:44:01 +0200915 ip4_elems = talloc_realloc(fi, gss->local.ip4, struct gprs_ns_ie_ip4_elem, count);
Alexander Couzense769f522020-12-07 07:37:07 +0100916 if (!ip4_elems)
917 return;
918
Alexander Couzens71128672021-06-05 18:44:01 +0200919 gss->local.ip4 = ip4_elems;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100920 llist_for_each_entry(sbind, &gss->binds, list) {
921 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100922 sa = gprs_ns2_ip_bind_sockaddr(bind);
923 if (!sa)
924 continue;
925
926 if (sa->u.sas.ss_family != AF_INET)
927 continue;
928
929 /* check if this is an specific bind */
930 if (sa->u.sin.sin_addr.s_addr == 0) {
931 if (osmo_sockaddr_local_ip(&local, remote))
932 continue;
933
934 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
935 } else {
936 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
937 }
938
939 ip4_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100940 ip4_elems->sig_weight = bind->sns_sig_weight;
941 ip4_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100942 ip4_elems++;
943 }
944
Alexander Couzens71128672021-06-05 18:44:01 +0200945 gss->local.num_ip4 = count;
946 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->local.num_ip4, 8);
Alexander Couzense769f522020-12-07 07:37:07 +0100947 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200948 case AF_INET6:
Alexander Couzense769f522020-12-07 07:37:07 +0100949 /* IPv6 */
Alexander Couzens71128672021-06-05 18:44:01 +0200950 ip6_elems = talloc_realloc(fi, gss->local.ip6, struct gprs_ns_ie_ip6_elem, count);
Alexander Couzense769f522020-12-07 07:37:07 +0100951 if (!ip6_elems)
952 return;
953
Alexander Couzens71128672021-06-05 18:44:01 +0200954 gss->local.ip6 = ip6_elems;
Alexander Couzense769f522020-12-07 07:37:07 +0100955
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100956 llist_for_each_entry(sbind, &gss->binds, list) {
957 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100958 sa = gprs_ns2_ip_bind_sockaddr(bind);
959 if (!sa)
960 continue;
961
962 if (sa->u.sas.ss_family != AF_INET6)
963 continue;
964
965 /* check if this is an specific bind */
966 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
967 if (osmo_sockaddr_local_ip(&local, remote))
968 continue;
969
970 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
971 } else {
972 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
973 }
974
975 ip6_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100976 ip6_elems->sig_weight = bind->sns_sig_weight;
977 ip6_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100978
979 ip6_elems++;
980 }
Alexander Couzens71128672021-06-05 18:44:01 +0200981 gss->local.num_ip6 = count;
982 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->local.num_ip6, 8);
Alexander Couzense769f522020-12-07 07:37:07 +0100983 break;
984 }
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200985
986 ns2_sns_copy_local_endpoints(gss);
Harald Welte24920e22021-03-04 13:03:27 +0100987}
988
Alexander Couzens6608ce92021-04-26 20:39:46 +0200989static void ns2_sns_choose_next_bind(struct ns2_sns_state *gss)
990{
991 /* take the first bind or take the next bind */
992 if (!gss->initial_bind || gss->initial_bind->list.next == &gss->binds)
993 gss->initial_bind = llist_first_entry_or_null(&gss->binds, struct ns2_sns_bind, list);
994 else
995 gss->initial_bind = llist_entry(gss->initial_bind->list.next, struct ns2_sns_bind, list);
996}
997
Harald Welte24920e22021-03-04 13:03:27 +0100998/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Harald Welte694dad52021-03-23 15:22:16 +0100999static void ns2_sns_st_bss_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Harald Welte24920e22021-03-04 13:03:27 +01001000{
1001 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1002
Harald Weltef61a9152021-03-02 22:20:17 +01001003 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1004
Harald Welte24920e22021-03-04 13:03:27 +01001005 /* on a generic failure, the timer callback will recover */
1006 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
1007 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_FAILURE);
Harald Welte694dad52021-03-23 15:22:16 +01001008 if (old_state != GPRS_SNS_ST_BSS_SIZE)
Harald Welte24920e22021-03-04 13:03:27 +01001009 gss->N = 0;
1010
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001011 ns2_clear_procedures(gss);
Harald Welte24920e22021-03-04 13:03:27 +01001012 gss->alive = false;
1013
1014 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens6608ce92021-04-26 20:39:46 +02001015 ns2_sns_choose_next_bind(gss);
Harald Welte24920e22021-03-04 13:03:27 +01001016
1017 /* setup the NSVC */
1018 if (!gss->sns_nsvc) {
1019 struct gprs_ns2_vc_bind *bind = gss->initial_bind->bind;
1020 struct osmo_sockaddr *remote = &gss->initial->saddr;
1021 gss->sns_nsvc = ns2_ip_bind_connect(bind, gss->nse, remote);
1022 if (!gss->sns_nsvc)
1023 return;
Harald Weltec962a2e2021-03-05 08:09:08 +01001024 /* A pre-configured endpoint shall not be used for NSE data or signalling traffic
1025 * (with the exception of Size and Configuration procedures) unless it is configured
1026 * by the SGSN using the auto-configuration procedures */
Harald Welte24920e22021-03-04 13:03:27 +01001027 gss->sns_nsvc->sns_only = true;
1028 }
1029
Alexander Couzens6a161492020-07-12 13:45:50 +02001030 if (gss->num_max_ip4_remote > 0)
Alexander Couzens71128672021-06-05 18:44:01 +02001031 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->local.num_ip4, -1);
Alexander Couzens6a161492020-07-12 13:45:50 +02001032 else
Alexander Couzens71128672021-06-05 18:44:01 +02001033 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, -1, gss->local.num_ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +02001034}
1035
Harald Welte694dad52021-03-23 15:22:16 +01001036static void ns2_sns_st_bss_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +02001037{
Harald Weltef61a9152021-03-02 22:20:17 +01001038 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens3df58862021-02-05 17:18:08 +01001039 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Harald Weltef61a9152021-03-02 22:20:17 +01001040 struct tlv_parsed *tp = NULL;
1041
1042 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
Alexander Couzens6a161492020-07-12 13:45:50 +02001043
1044 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001045 case NS2_SNS_EV_RX_CONFIG_ACK:
Alexander Couzens6a161492020-07-12 13:45:50 +02001046 tp = (struct tlv_parsed *) data;
1047 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
1048 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
1049 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
1050 /* TODO: What to do? */
1051 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001052 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_SGSN, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 3);
Alexander Couzens6a161492020-07-12 13:45:50 +02001053 }
1054 break;
1055 default:
1056 OSMO_ASSERT(0);
1057 }
1058}
1059
Harald Welte694dad52021-03-23 15:22:16 +01001060static void ns2_sns_st_bss_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Alexander Couzens6a161492020-07-12 13:45:50 +02001061{
1062 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens790a9632021-02-05 17:18:39 +01001063
Harald Weltef61a9152021-03-02 22:20:17 +01001064 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1065
Harald Welte694dad52021-03-23 15:22:16 +01001066 if (old_state != GPRS_SNS_ST_BSS_CONFIG_BSS)
Alexander Couzens790a9632021-02-05 17:18:39 +01001067 gss->N = 0;
1068
Alexander Couzens6a161492020-07-12 13:45:50 +02001069 /* Transmit SNS-CONFIG */
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001070 switch (gss->family) {
1071 case AF_INET:
Alexander Couzens6a161492020-07-12 13:45:50 +02001072 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzens71128672021-06-05 18:44:01 +02001073 gss->local.ip4, gss->local.num_ip4,
Alexander Couzense78207f2020-12-07 06:19:29 +01001074 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02001075 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001076 case AF_INET6:
Alexander Couzens6a161492020-07-12 13:45:50 +02001077 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +01001078 NULL, 0,
Alexander Couzens71128672021-06-05 18:44:01 +02001079 gss->local.ip6, gss->local.num_ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +02001080 break;
1081 }
1082}
1083
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001084/* calculate the timeout of the configured state. the configured
1085 * state will fail if not at least one NS-VC is alive within X second.
1086 */
1087static inline int ns_sns_configured_timeout(struct osmo_fsm_inst *fi)
1088{
1089 int secs;
1090 struct gprs_ns2_inst *nsi = nse_inst_from_fi(fi)->nsi;
1091 secs = nsi->timeout[NS_TOUT_TNS_ALIVE] * nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES];
1092 secs += nsi->timeout[NS_TOUT_TNS_TEST];
1093
1094 return secs;
1095}
Alexander Couzens6a161492020-07-12 13:45:50 +02001096
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001097/* append the remote endpoints from the parsed TLV array to the ns2_sns_state */
1098static int ns_sns_append_remote_eps(struct osmo_fsm_inst *fi, const struct tlv_parsed *tp)
Alexander Couzens6a161492020-07-12 13:45:50 +02001099{
1100 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001101
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001102 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1103 const struct gprs_ns_ie_ip4_elem *v4_list;
1104 unsigned int num_v4;
1105 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1106 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Alexander Couzens6a161492020-07-12 13:45:50 +02001107
Alexander Couzens71128672021-06-05 18:44:01 +02001108 if (num_v4 && gss->remote.ip6)
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001109 return -NS_CAUSE_INVAL_NR_IPv4_EP;
Alexander Couzens6a161492020-07-12 13:45:50 +02001110
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001111 /* realloc to the new size */
Alexander Couzens71128672021-06-05 18:44:01 +02001112 gss->remote.ip4 = talloc_realloc(gss, gss->remote.ip4,
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001113 struct gprs_ns_ie_ip4_elem,
Alexander Couzens71128672021-06-05 18:44:01 +02001114 gss->remote.num_ip4 + num_v4);
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001115 /* append the new entries to the end of the list */
Alexander Couzens71128672021-06-05 18:44:01 +02001116 memcpy(&gss->remote.ip4[gss->remote.num_ip4], v4_list, num_v4*sizeof(*v4_list));
1117 gss->remote.num_ip4 += num_v4;
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001118
1119 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
Alexander Couzens71128672021-06-05 18:44:01 +02001120 gss->remote.num_ip4);
Alexander Couzens6a161492020-07-12 13:45:50 +02001121 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001122
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001123 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1124 const struct gprs_ns_ie_ip6_elem *v6_list;
1125 unsigned int num_v6;
1126 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1127 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
1128
Alexander Couzens71128672021-06-05 18:44:01 +02001129 if (num_v6 && gss->remote.ip4)
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001130 return -NS_CAUSE_INVAL_NR_IPv6_EP;
1131
1132 /* realloc to the new size */
Alexander Couzens71128672021-06-05 18:44:01 +02001133 gss->remote.ip6 = talloc_realloc(gss, gss->remote.ip6,
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001134 struct gprs_ns_ie_ip6_elem,
Alexander Couzens71128672021-06-05 18:44:01 +02001135 gss->remote.num_ip6 + num_v6);
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001136 /* append the new entries to the end of the list */
Alexander Couzens71128672021-06-05 18:44:01 +02001137 memcpy(&gss->remote.ip6[gss->remote.num_ip6], v6_list, num_v6*sizeof(*v6_list));
1138 gss->remote.num_ip6 += num_v6;
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001139
Alexander Couzens71128672021-06-05 18:44:01 +02001140 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %d entries\n",
1141 gss->remote.num_ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +02001142 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001143
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001144 return 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02001145}
1146
Harald Welte694dad52021-03-23 15:22:16 +01001147static void ns2_sns_st_bss_config_sgsn_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Alexander Couzens790a9632021-02-05 17:18:39 +01001148{
1149 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1150
Harald Weltef61a9152021-03-02 22:20:17 +01001151 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1152
Harald Welte694dad52021-03-23 15:22:16 +01001153 if (old_state != GPRS_SNS_ST_BSS_CONFIG_SGSN)
Alexander Couzens790a9632021-02-05 17:18:39 +01001154 gss->N = 0;
1155}
1156
Harald Welte694dad52021-03-23 15:22:16 +01001157static void ns2_sns_st_bss_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +02001158{
1159 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001160 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1161 uint8_t cause;
1162 int rc;
Alexander Couzens6a161492020-07-12 13:45:50 +02001163
Harald Weltef61a9152021-03-02 22:20:17 +01001164 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1165
Alexander Couzens6a161492020-07-12 13:45:50 +02001166 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001167 case NS2_SNS_EV_RX_CONFIG_END:
1168 case NS2_SNS_EV_RX_CONFIG:
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001169 rc = ns_sns_append_remote_eps(fi, data);
1170 if (rc < 0) {
1171 cause = -rc;
1172 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
1173 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
1174 return;
Alexander Couzens6a161492020-07-12 13:45:50 +02001175 }
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001176 if (event == NS2_SNS_EV_RX_CONFIG_END) {
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001177 /* check if sum of data / sig weights == 0 */
Alexander Couzens019da4b2021-06-06 02:48:18 +02001178 if (ip46_weight_sum_data(&gss->remote) == 0 || ip46_weight_sum_sig(&gss->remote) == 0) {
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001179 cause = NS_CAUSE_INVAL_WEIGH;
1180 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
1181 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
1182 return;
1183 }
1184 create_missing_nsvcs(fi);
1185 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
1186 /* start the test procedure on ALL NSVCs! */
1187 gprs_ns2_start_alive_all_nsvcs(nse);
1188 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
1189 } else {
1190 /* just send CONFIG-ACK */
1191 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
1192 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02001193 }
1194 break;
1195 default:
1196 OSMO_ASSERT(0);
1197 }
1198}
1199
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001200/* called when receiving NS2_SNS_EV_RX_ADD in state configure */
Alexander Couzens6a161492020-07-12 13:45:50 +02001201static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1202 struct ns2_sns_state *gss,
1203 struct tlv_parsed *tp)
1204{
1205 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1206 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1207 int num_v4 = 0, num_v6 = 0;
1208 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001209 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001210 int rc = 0;
1211
1212 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1213 * check uniqueness within the lists (no doublicate entries)
1214 * check not-known-by-us and sent back a list of unknown/known values
1215 * (abnormal behaviour according to 48.016)
1216 */
1217
1218 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001219 if (gss->family == AF_INET) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001220 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1221 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1222 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1223 return;
1224 }
1225
1226 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1227 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001228 for (i = 0; i < num_v4; i++) {
1229 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001230 rc = do_sns_add(fi, &v4_list[i], NULL);
1231 if (rc < 0) {
1232 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001233 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001234 do_sns_delete(fi, &v4_list[j], NULL);
1235 cause = -rc;
1236 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1237 break;
1238 }
1239 }
1240 } else { /* IPv6 */
1241 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1242 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1243 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1244 return;
1245 }
1246
1247 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1248 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001249 for (i = 0; i < num_v6; i++) {
1250 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001251 rc = do_sns_add(fi, NULL, &v6_list[i]);
1252 if (rc < 0) {
1253 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001254 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001255 do_sns_delete(fi, NULL, &v6_list[j]);
1256 cause = -rc;
1257 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1258 break;
1259 }
1260 }
1261 }
1262
1263 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1264 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1265}
1266
1267static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1268 struct ns2_sns_state *gss,
1269 struct tlv_parsed *tp)
1270{
1271 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1272 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1273 int num_v4 = 0, num_v6 = 0;
1274 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001275 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001276 int rc = 0;
1277
1278 /* TODO: split up delete into v4 + v6
1279 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1280 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1281 */
1282 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001283 if (gss->family == AF_INET) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001284 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1285 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1286 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001287 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001288 rc = do_sns_delete(fi, &v4_list[i], NULL);
1289 if (rc < 0) {
1290 cause = -rc;
1291 /* continue to delete others */
1292 }
1293 }
1294 if (cause != 0xff) {
1295 /* TODO: create list of not-deleted and return it */
1296 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1297 return;
1298 }
1299
1300 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1301 /* delete all NS-VCs for given IPv4 address */
1302 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1303 struct gprs_ns_ie_ip4_elem *ip4_remote;
1304 uint32_t ip_addr = *(uint32_t *)(ie+1);
1305 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1306 cause = NS_CAUSE_UNKN_IP_ADDR;
1307 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1308 return;
1309 }
1310 /* make a copy as do_sns_delete() will change the array underneath us */
Alexander Couzens71128672021-06-05 18:44:01 +02001311 ip4_remote = talloc_memdup(fi, gss->remote.ip4,
1312 gss->remote.num_ip4 * sizeof(*v4_list));
1313 for (i = 0; i < gss->remote.num_ip4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001314 if (ip4_remote[i].ip_addr == ip_addr) {
1315 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1316 if (rc < 0) {
1317 cause = -rc;
1318 /* continue to delete others */
1319 }
1320 }
1321 }
1322 talloc_free(ip4_remote);
1323 if (cause != 0xff) {
1324 /* TODO: create list of not-deleted and return it */
1325 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1326 return;
1327 }
1328 } else {
1329 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1330 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1331 return;
1332 }
1333 } else { /* IPv6 */
1334 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1335 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1336 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001337 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001338 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1339 if (rc < 0) {
1340 cause = -rc;
1341 /* continue to delete others */
1342 }
1343 }
1344 if (cause != 0xff) {
1345 /* TODO: create list of not-deleted and return it */
1346 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1347 return;
1348 }
1349 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1350 /* delete all NS-VCs for given IPv4 address */
1351 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1352 struct gprs_ns_ie_ip6_elem *ip6_remote;
1353 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001354 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001355 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1356 cause = NS_CAUSE_UNKN_IP_ADDR;
1357 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1358 return;
1359 }
1360 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1361 /* make a copy as do_sns_delete() will change the array underneath us */
Alexander Couzens71128672021-06-05 18:44:01 +02001362 ip6_remote = talloc_memdup(fi, gss->remote.ip6,
1363 gss->remote.num_ip6 * sizeof(*v4_list));
1364 for (i = 0; i < gss->remote.num_ip6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001365 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1366 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1367 if (rc < 0) {
1368 cause = -rc;
1369 /* continue to delete others */
1370 }
1371 }
1372 }
1373
1374 talloc_free(ip6_remote);
1375 if (cause != 0xff) {
1376 /* TODO: create list of not-deleted and return it */
1377 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1378 return;
1379 }
1380 } else {
1381 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1382 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1383 return;
1384 }
1385 }
1386 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1387}
1388
1389static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1390 struct ns2_sns_state *gss,
1391 struct tlv_parsed *tp)
1392{
1393 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1394 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1395 int num_v4 = 0, num_v6 = 0;
1396 uint8_t trans_id, cause = 0xff;
1397 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001398 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001399
1400 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1401 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1402 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1403 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001404 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001405 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1406 if (rc < 0) {
1407 cause = -rc;
1408 /* continue to others */
1409 }
1410 }
1411 if (cause != 0xff) {
1412 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1413 return;
1414 }
1415 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1416 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1417 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001418 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001419 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1420 if (rc < 0) {
1421 cause = -rc;
1422 /* continue to others */
1423 }
1424 }
1425 if (cause != 0xff) {
1426 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1427 return;
1428 }
1429 } else {
1430 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1431 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1432 return;
1433 }
1434 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1435}
1436
1437static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1438{
1439 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1440 struct tlv_parsed *tp = data;
1441
1442 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001443 case NS2_SNS_EV_RX_ADD:
Alexander Couzens6a161492020-07-12 13:45:50 +02001444 ns2_sns_st_configured_add(fi, gss, tp);
1445 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001446 case NS2_SNS_EV_RX_DELETE:
Alexander Couzens6a161492020-07-12 13:45:50 +02001447 ns2_sns_st_configured_delete(fi, gss, tp);
1448 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001449 case NS2_SNS_EV_RX_CHANGE_WEIGHT:
Alexander Couzens6a161492020-07-12 13:45:50 +02001450 ns2_sns_st_configured_change(fi, gss, tp);
1451 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001452 case NS2_SNS_EV_REQ_NSVC_ALIVE:
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001453 osmo_timer_del(&fi->timer);
1454 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001455 }
1456}
1457
1458static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1459{
Alexander Couzenscdb2baa2021-04-01 15:29:16 +02001460 struct gprs_ns2_vc *nsvc;
1461 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001462 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzenscdb2baa2021-04-01 15:29:16 +02001463 /* NS-VC status updates are only parsed in ST_CONFIGURED.
1464 * Do an initial check if there are any nsvc alive atm */
1465 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1466 if (ns2_vc_is_unblocked(nsvc)) {
1467 gss->alive = true;
1468 osmo_timer_del(&fi->timer);
1469 break;
1470 }
1471 }
1472
Alexander Couzens53e70092021-04-06 15:45:47 +02001473 /* remove the initial NSVC if the NSVC isn't part of the configuration */
1474 if (gss->sns_nsvc->sns_only)
1475 gprs_ns2_free_nsvc(gss->sns_nsvc);
1476
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001477 if (old_state != GPRS_SNS_ST_LOCAL_PROCEDURE)
1478 ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);
1479
1480 if (!llist_empty(&gss->procedures)) {
1481 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
1482 gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1483 }
1484}
1485
1486static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1487{
1488 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1489
1490 /* check if resend or not */
1491 if (!gss->current_procedure) {
1492 /* take next procedure */
1493 gss->current_procedure = llist_first_entry_or_null(&gss->procedures,
1494 struct ns2_sns_procedure, list);
1495 if (!gss->current_procedure) {
1496 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
1497 return;
1498 }
1499 gss->N = 0;
1500 gss->current_procedure->running = true;
1501 gss->current_procedure->trans_id = ++gss->trans_id;
1502 if (gss->trans_id == 0)
1503 gss->trans_id = gss->current_procedure->trans_id = 1;
1504
1505 }
1506
1507 /* also takes care of retransmitting */
1508 switch (gss->current_procedure->procedure) {
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001509 case SNS_PROC_ADD:
1510 if (gss->family == AF_INET)
1511 ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
1512 else
1513 ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
1514 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001515 case SNS_PROC_CHANGE_WEIGHT:
1516 if (gss->family == AF_INET)
1517 ns2_tx_sns_change_weight(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
1518 else
1519 ns2_tx_sns_change_weight(gss->sns_nsvc, gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
1520 break;
Alexander Couzensdb07a442021-06-06 18:58:01 +02001521 case SNS_PROC_DEL:
1522 if (gss->family == AF_INET)
1523 ns2_tx_sns_del(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
1524 else
1525 ns2_tx_sns_del(gss->sns_nsvc, gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
1526 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001527 default:
1528 break;
1529 }
1530}
1531
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001532static void create_nsvc_for_new_sbind(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind)
1533{
1534 struct gprs_ns2_nse *nse = gss->nse;
1535 struct gprs_ns2_vc_bind *bind = sbind->bind;
1536 struct gprs_ns2_vc *nsvc;
1537 struct osmo_sockaddr remote = { };
1538 unsigned int i;
1539
1540 /* iterate over all remote IPv4 endpoints */
1541 for (i = 0; i < gss->remote.num_ip4; i++) {
1542 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->remote.ip4[i];
1543
1544 remote.u.sin.sin_family = AF_INET;
1545 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
1546 remote.u.sin.sin_port = ip4->udp_port;
1547 /* we only care about UDP binds */
1548 if (bind->ll != GPRS_NS2_LL_UDP)
1549 continue;
1550
1551 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
1552 if (!nsvc) {
1553 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
1554 if (!nsvc) {
1555 /* TODO: add to a list to send back a NS-STATUS */
1556 continue;
1557 }
1558 }
1559
1560 /* update data / signalling weight */
1561 nsvc->data_weight = ip4->data_weight;
1562 nsvc->sig_weight = ip4->sig_weight;
1563 nsvc->sns_only = false;
1564 }
1565
1566 /* iterate over all remote IPv4 endpoints */
1567 for (i = 0; i < gss->remote.num_ip6; i++) {
1568 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->remote.ip6[i];
1569
1570 remote.u.sin6.sin6_family = AF_INET6;
1571 remote.u.sin6.sin6_addr = ip6->ip_addr;
1572 remote.u.sin6.sin6_port = ip6->udp_port;
1573
1574 /* we only care about UDP binds */
1575 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
1576 if (!nsvc) {
1577 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
1578 if (!nsvc) {
1579 /* TODO: add to a list to send back a NS-STATUS */
1580 continue;
1581 }
1582 }
1583
1584 /* update data / signalling weight */
1585 nsvc->data_weight = ip6->data_weight;
1586 nsvc->sig_weight = ip6->sig_weight;
1587 nsvc->sns_only = false;
1588 }
1589}
1590
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001591static void ns2_sns_st_local_procedure(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1592{
1593 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1594 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1595 struct gprs_ns_ie_ip4_elem *ip4, *proc4;
1596 struct gprs_ns_ie_ip6_elem *ip6, *proc6;
1597 struct tlv_parsed *tp = data;
1598 uint8_t trans_id;
1599 uint8_t cause;
1600
1601 switch (event) {
1602 case NS2_SNS_EV_RX_ADD:
1603 ns2_sns_st_configured_add(fi, gss, tp);
1604 break;
1605 case NS2_SNS_EV_RX_DELETE:
1606 ns2_sns_st_configured_delete(fi, gss, tp);
1607 break;
1608 case NS2_SNS_EV_RX_CHANGE_WEIGHT:
1609 ns2_sns_st_configured_change(fi, gss, tp);
1610 break;
1611 case NS2_SNS_EV_RX_ACK:
1612 /* presence of trans_id is already checked here */
1613 trans_id = tlvp_val8(tp, NS_IE_TRANS_ID, 0);
1614 if (trans_id != gss->current_procedure->trans_id) {
1615 LOGPFSML(fi, LOGL_INFO, "NSEI=%u Rx SNS ACK with invalid transaction id %d. Valid %d\n",
1616 nse->nsei, trans_id, gss->current_procedure->trans_id);
1617 break;
1618 }
1619
1620 if (TLVP_PRESENT(tp, NS_IE_CAUSE)) {
1621 /* what happend on error cause? return to size? */
1622 cause = tlvp_val8(tp, NS_IE_CAUSE, 0);
1623 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx SNS ACK trans %d with cause code %d.\n",
1624 nse->nsei, trans_id, cause);
1625 sns_failed(fi, NULL);
1626 break;
1627 }
1628
1629 switch (gss->current_procedure->procedure) {
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001630 case SNS_PROC_ADD:
1631 switch (gss->family) {
1632 case AF_INET:
1633 add_ip4_elem(gss, &gss->local, &gss->current_procedure->ip4);
1634 break;
1635 case AF_INET6:
1636 add_ip6_elem(gss, &gss->local, &gss->current_procedure->ip6);
1637 break;
1638 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02001639 /* the sbind can be NULL if the bind has been released by del_bind */
1640 if (gss->current_procedure->sbind) {
1641 create_nsvc_for_new_sbind(gss, gss->current_procedure->sbind);
1642 gprs_ns2_start_alive_all_nsvcs(nse);
1643 }
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001644 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001645 case SNS_PROC_CHANGE_WEIGHT:
1646 switch (gss->family) {
1647 case AF_INET:
1648 proc4 = &gss->current_procedure->ip4;
1649 for (unsigned int i=0; i<gss->local.num_ip4; i++) {
1650 ip4 = &gss->local.ip4[i];
1651 if (ip4->ip_addr != proc4->ip_addr ||
1652 ip4->udp_port != proc4->udp_port)
1653 continue;
1654 ip4->sig_weight = proc4->sig_weight;
1655 ip4->data_weight = proc4->data_weight;
1656 break;
1657 }
1658 break;
1659 case AF_INET6:
1660 proc6 = &gss->current_procedure->ip6;
1661 for (unsigned int i=0; i<gss->local.num_ip6; i++) {
1662 ip6 = &gss->local.ip6[i];
1663 if (memcmp(&ip6->ip_addr, &proc6->ip_addr, sizeof(proc6->ip_addr)) ||
1664 ip6->udp_port != proc6->udp_port) {
1665 continue;
1666 }
1667 ip6->sig_weight = proc6->sig_weight;
1668 ip6->data_weight = proc6->data_weight;
1669 break;
1670 }
1671 break;
1672 default:
1673 OSMO_ASSERT(0);
1674 }
1675 break;
Alexander Couzensdb07a442021-06-06 18:58:01 +02001676 case SNS_PROC_DEL:
1677 switch (gss->family) {
1678 case AF_INET:
1679 remove_ip4_elem(gss, &gss->local, &gss->current_procedure->ip4);
1680 break;
1681 case AF_INET6:
1682 remove_ip6_elem(gss, &gss->local, &gss->current_procedure->ip6);
1683 break;
1684 }
1685 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001686 default:
1687 break;
1688 }
1689
1690 llist_del(&gss->current_procedure->list);
1691 talloc_free(gss->current_procedure);
1692 gss->current_procedure = NULL;
1693
1694 if (llist_empty(&gss->procedures))
1695 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_CONFIGURED,
1696 0, 0);
1697 else
1698 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
1699 gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1700 break;
1701 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001702}
1703
1704static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1705 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001706 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens0a7c5ee2021-04-10 18:20:21 +02001707 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1708 S(GPRS_SNS_ST_BSS_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001709 .name = "UNCONFIGURED",
Harald Welte694dad52021-03-23 15:22:16 +01001710 .action = ns2_sns_st_bss_unconfigured,
Alexander Couzens6a161492020-07-12 13:45:50 +02001711 },
Harald Welte694dad52021-03-23 15:22:16 +01001712 [GPRS_SNS_ST_BSS_SIZE] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001713 .in_event_mask = S(NS2_SNS_EV_RX_SIZE_ACK),
Alexander Couzens6a161492020-07-12 13:45:50 +02001714 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001715 S(GPRS_SNS_ST_BSS_SIZE) |
1716 S(GPRS_SNS_ST_BSS_CONFIG_BSS),
1717 .name = "BSS_SIZE",
1718 .action = ns2_sns_st_bss_size,
1719 .onenter = ns2_sns_st_bss_size_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001720 },
Harald Welte694dad52021-03-23 15:22:16 +01001721 [GPRS_SNS_ST_BSS_CONFIG_BSS] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001722 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG_ACK),
Alexander Couzens6a161492020-07-12 13:45:50 +02001723 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001724 S(GPRS_SNS_ST_BSS_CONFIG_BSS) |
1725 S(GPRS_SNS_ST_BSS_CONFIG_SGSN) |
1726 S(GPRS_SNS_ST_BSS_SIZE),
1727 .name = "BSS_CONFIG_BSS",
1728 .action = ns2_sns_st_bss_config_bss,
1729 .onenter = ns2_sns_st_bss_config_bss_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001730 },
Harald Welte694dad52021-03-23 15:22:16 +01001731 [GPRS_SNS_ST_BSS_CONFIG_SGSN] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001732 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG) |
1733 S(NS2_SNS_EV_RX_CONFIG_END),
Alexander Couzens6a161492020-07-12 13:45:50 +02001734 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001735 S(GPRS_SNS_ST_BSS_CONFIG_SGSN) |
Alexander Couzens6a161492020-07-12 13:45:50 +02001736 S(GPRS_SNS_ST_CONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001737 S(GPRS_SNS_ST_BSS_SIZE),
1738 .name = "BSS_CONFIG_SGSN",
1739 .action = ns2_sns_st_bss_config_sgsn,
1740 .onenter = ns2_sns_st_bss_config_sgsn_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001741 },
1742 [GPRS_SNS_ST_CONFIGURED] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001743 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
1744 S(NS2_SNS_EV_RX_DELETE) |
1745 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
1746 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
Alexander Couzense03d8632020-12-06 03:31:44 +01001747 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001748 S(GPRS_SNS_ST_BSS_SIZE) |
1749 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001750 .name = "CONFIGURED",
1751 .action = ns2_sns_st_configured,
1752 .onenter = ns2_sns_st_configured_onenter,
1753 },
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001754 [GPRS_SNS_ST_LOCAL_PROCEDURE] = {
1755 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
1756 S(NS2_SNS_EV_RX_DELETE) |
1757 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
1758 S(NS2_SNS_EV_RX_ACK) |
1759 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
1760 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1761 S(GPRS_SNS_ST_BSS_SIZE) |
1762 S(GPRS_SNS_ST_CONFIGURED) |
1763 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
1764 .name = "LOCAL_PROCEDURE",
1765 .action = ns2_sns_st_local_procedure,
1766 .onenter = ns2_sns_st_local_procedure_onenter,
1767 },
1768
Alexander Couzens6a161492020-07-12 13:45:50 +02001769};
1770
1771static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1772{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001773 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001774 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1775 struct gprs_ns2_inst *nsi = nse->nsi;
1776
Alexander Couzens90ee9632020-12-07 06:18:32 +01001777 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001778 switch (fi->T) {
1779 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001780 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001781 sns_failed(fi, "Size retries failed. Selecting next IP-SNS endpoint.");
Alexander Couzensa367d082020-12-21 14:06:24 +01001782 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001783 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001784 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001785 break;
1786 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001787 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001788 sns_failed(fi, "BSS Config retries failed. Selecting next IP-SNS endpoint");
Alexander Couzensa367d082020-12-21 14:06:24 +01001789 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001790 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
Alexander Couzensa367d082020-12-21 14:06:24 +01001791 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001792 break;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001793 case 3:
Alexander Couzens3df58862021-02-05 17:18:08 +01001794 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001795 sns_failed(fi, "SGSN Config retries failed. Selecting next IP-SNS endpoint.");
Alexander Couzens3df58862021-02-05 17:18:08 +01001796 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001797 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_SGSN, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
Alexander Couzens3df58862021-02-05 17:18:08 +01001798 }
1799 break;
1800 case 4:
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001801 sns_failed(fi, "Config succeeded but no NS-VC came online. Selecting next IP-SNS endpoint.");
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001802 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001803 case 5:
1804 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1805 sns_failed(fi, "SNS Procedure retries failed.");
1806 } else {
1807 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1808 }
1809 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001810 }
1811 return 0;
1812}
1813
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001814static struct gprs_ns_ie_ip4_elem *ns2_get_sbind_ip4_entry(struct ns2_sns_state *gss,
1815 struct ns2_sns_bind *sbind,
1816 struct ns2_sns_elems *endpoints)
1817{
1818 const struct osmo_sockaddr *addr;
1819 struct gprs_ns_ie_ip4_elem *ip4;
1820
1821 if (gss->family != AF_INET)
1822 return NULL;
1823
1824 addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1825 if (addr->u.sa.sa_family != AF_INET)
1826 return NULL;
1827
1828 for (unsigned int i=0; i<endpoints->num_ip4; i++) {
1829 ip4 = &endpoints->ip4[i];
1830 if (ip4->ip_addr == addr->u.sin.sin_addr.s_addr &&
1831 ip4->udp_port == addr->u.sin.sin_port)
1832 return ip4;
1833 }
1834
1835 return NULL;
1836}
1837
1838static struct gprs_ns_ie_ip6_elem *ns2_get_sbind_ip6_entry(struct ns2_sns_state *gss,
1839 struct ns2_sns_bind *sbind,
1840 struct ns2_sns_elems *endpoints)
1841{
1842 const struct osmo_sockaddr *addr;
1843 struct gprs_ns_ie_ip6_elem *ip6;
1844
1845 if (gss->family != AF_INET6)
1846 return NULL;
1847
1848 addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1849 if (addr->u.sa.sa_family != AF_INET6)
1850 return NULL;
1851
1852 for (unsigned int i=0; i<endpoints->num_ip6; i++) {
1853 ip6 = &endpoints->ip6[i];
1854 if (memcmp(&ip6->ip_addr, &addr->u.sin6.sin6_addr, sizeof(ip6->ip_addr)) ||
1855 ip6->udp_port != addr->u.sin6.sin6_port)
1856 return ip6;
1857 }
1858
1859 return NULL;
1860}
1861
1862/* return != 0 if the resulting weight is invalid. return 1 if sbind doesn't have an entry */
1863static int ns2_update_weight_entry(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
1864 struct ns2_sns_elems *endpoints)
1865{
1866 struct gprs_ns_ie_ip4_elem *ip4;
1867 struct gprs_ns_ie_ip6_elem *ip6;
1868
1869 switch (gss->family) {
1870 case AF_INET:
1871 ip4 = ns2_get_sbind_ip4_entry(gss, sbind, endpoints);
1872 if (!ip4)
1873 return 1;
1874 ip4->sig_weight = sbind->bind->sns_sig_weight;
1875 ip4->data_weight = sbind->bind->sns_data_weight;
1876 return (ip4_weight_sum_sig(endpoints) != 0 && ip4_weight_sum_data(endpoints) != 0);
1877 break;
1878 case AF_INET6:
1879 ip6 = ns2_get_sbind_ip6_entry(gss, sbind, endpoints);
1880 if (!ip6)
1881 return 1;
1882 ip6->sig_weight = sbind->bind->sns_sig_weight;
1883 ip6->data_weight = sbind->bind->sns_data_weight;
1884 return (ip6_weight_sum_sig(endpoints) != 0 && ip6_weight_sum_data(endpoints) != 0);
1885 break;
1886 default:
1887 OSMO_ASSERT(0);
1888 }
1889}
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001890static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
1891 enum sns_procedure procedure_type)
1892{
1893 struct ns2_sns_procedure *procedure = NULL;
1894 const struct osmo_sockaddr *saddr;
1895 saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1896
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001897 OSMO_ASSERT(saddr->u.sa.sa_family == gss->family);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001898
1899 switch (procedure_type) {
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001900 case SNS_PROC_ADD:
1901 break;
Alexander Couzensdb07a442021-06-06 18:58:01 +02001902 case SNS_PROC_DEL:
1903 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001904 case SNS_PROC_CHANGE_WEIGHT:
1905 llist_for_each_entry(procedure, &gss->procedures, list) {
1906 if (procedure->sbind == sbind && procedure->procedure == procedure_type &&
1907 !procedure->running) {
1908 switch(gss->family) {
1909 case AF_INET:
1910 /* merge it with a previous procedure */
1911 procedure->ip4.ip_addr = sbind->bind->sns_sig_weight;
1912 procedure->ip4.data_weight = sbind->bind->sns_data_weight;
1913 break;
1914 case AF_INET6:
1915 /* merge it with a previous procedure */
1916 procedure->ip6.sig_weight = sbind->bind->sns_sig_weight;
1917 procedure->ip6.data_weight = sbind->bind->sns_data_weight;
1918 break;
1919 default:
1920 OSMO_ASSERT(0);
1921 }
1922 return;
1923 }
1924 }
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001925 break;
1926 default:
1927 return;
1928 }
1929
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001930 procedure = talloc_zero(gss, struct ns2_sns_procedure);
1931 if (!procedure)
1932 return;
1933
Alexander Couzensdb07a442021-06-06 18:58:01 +02001934 switch (procedure_type) {
1935 case SNS_PROC_ADD:
1936 case SNS_PROC_CHANGE_WEIGHT:
1937 procedure->sbind = sbind;
1938 break;
1939 default:
1940 break;
1941 }
1942
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001943 llist_add_tail(&procedure->list, &gss->procedures);
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001944 procedure->procedure = procedure_type;
1945 procedure->sig_weight = sbind->bind->sns_sig_weight;
1946 procedure->data_weight = sbind->bind->sns_data_weight;
1947
1948 switch(gss->family) {
1949 case AF_INET:
1950 procedure->ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
1951 procedure->ip4.udp_port = saddr->u.sin.sin_port;
1952 procedure->ip4.sig_weight = sbind->bind->sns_sig_weight;
1953 procedure->ip4.data_weight = sbind->bind->sns_data_weight;
1954 break;
1955 case AF_INET6:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001956 memcpy(&procedure->ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));
1957 procedure->ip6.udp_port = saddr->u.sin.sin_port;
1958 procedure->ip6.sig_weight = sbind->bind->sns_sig_weight;
1959 procedure->ip6.data_weight = sbind->bind->sns_data_weight;
1960 break;
1961 default:
1962 OSMO_ASSERT(0);
1963 }
1964
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001965 if (gss->nse->bss_sns_fi->state == GPRS_SNS_ST_CONFIGURED) {
1966 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
1967 gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1968 }
1969}
1970
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001971/* add an entrypoint to sns_endpoints */
1972static int ns2_sns_add_elements(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
1973 struct ns2_sns_elems *elems)
1974{
1975 const struct osmo_sockaddr *saddr;
1976 struct gprs_ns_ie_ip4_elem ip4;
1977 struct gprs_ns_ie_ip6_elem ip6;
1978 int rc = -1;
1979
1980 saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1981 OSMO_ASSERT(saddr->u.sa.sa_family == gss->family);
1982
1983 switch (gss->family) {
1984 case AF_INET:
1985 ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
1986 ip4.udp_port= saddr->u.sin.sin_port;
1987 ip4.sig_weight = sbind->bind->sns_sig_weight;
1988 ip4.data_weight = sbind->bind->sns_data_weight;
1989 rc = add_ip4_elem(gss, elems, &ip4);
1990 break;
1991 case AF_INET6:
1992 memcpy(&ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));
1993 ip6.udp_port= saddr->u.sin.sin_port;
1994 ip6.sig_weight = sbind->bind->sns_sig_weight;
1995 ip6.data_weight = sbind->bind->sns_data_weight;
1996 rc = add_ip6_elem(gss, elems, &ip6);
1997 break;
1998 }
1999
2000 return rc;
2001}
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002002
Harald Welte9e37bf42021-03-02 20:48:31 +01002003/* common allstate-action for both roles */
Alexander Couzens6a161492020-07-12 13:45:50 +02002004static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2005{
2006 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002007 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002008 struct ns2_sns_bind *sbind;
2009 struct gprs_ns2_vc *nsvc, *nsvc2;
Alexander Couzensdb07a442021-06-06 18:58:01 +02002010 struct ns2_sns_procedure *procedure;
Alexander Couzens6a161492020-07-12 13:45:50 +02002011
Alexander Couzense769f522020-12-07 07:37:07 +01002012 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002013 case NS2_SNS_EV_REQ_ADD_BIND:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002014 sbind = data;
2015 switch (fi->state) {
2016 case GPRS_SNS_ST_UNCONFIGURED:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002017 if (gss->role == GPRS_SNS_ROLE_BSS)
2018 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002019 break;
Harald Welte694dad52021-03-23 15:22:16 +01002020 case GPRS_SNS_ST_BSS_SIZE:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002021 switch (gss->family) {
2022 case AF_INET:
2023 if (gss->num_max_ip4_remote <= gss->local.num_ip4 ||
2024 gss->num_max_ip4_remote * (gss->local.num_ip4 + 1) > gss->num_max_nsvcs) {
2025 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER);
2026 return;
2027 }
2028 break;
2029 case AF_INET6:
2030 if (gss->num_max_ip6_remote <= gss->local.num_ip6 ||
2031 gss->num_max_ip6_remote * (gss->local.num_ip6 + 1) > gss->num_max_nsvcs) {
2032 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER);
2033 return;
2034 }
2035 break;
2036 }
2037 ns2_sns_add_elements(gss, sbind, &gss->local);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002038 break;
Harald Welte694dad52021-03-23 15:22:16 +01002039 case GPRS_SNS_ST_BSS_CONFIG_BSS:
2040 case GPRS_SNS_ST_BSS_CONFIG_SGSN:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002041 case GPRS_SNS_ST_CONFIGURED:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002042 switch (gss->family) {
2043 case AF_INET:
2044 if (gss->num_max_ip4_remote <= gss->local.num_ip4) {
2045 LOGPFSML(fi, LOGL_ERROR,
2046 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2047 nse->nsei, sbind->bind->name);
2048 return;
2049 }
2050 if (gss->remote.num_ip4 * (gss->local.num_ip4 + 1) > gss->num_max_nsvcs) {
2051 LOGPFSML(fi, LOGL_ERROR,
2052 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2053 nse->nsei, sbind->bind->name);
2054 return;
2055 }
2056 break;
2057 case AF_INET6:
2058 if (gss->num_max_ip6_remote <= gss->local.num_ip6) {
2059 LOGPFSML(fi, LOGL_ERROR,
2060 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2061 nse->nsei, sbind->bind->name);
2062 return;
2063 }
2064 if (gss->remote.num_ip6 * (gss->local.num_ip6 + 1) > gss->num_max_nsvcs) {
2065 LOGPFSML(fi, LOGL_ERROR,
2066 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2067 nse->nsei, sbind->bind->name);
2068 return;
2069 }
2070 break;
2071 }
2072 ns2_sns_add_elements(gss, sbind, &gss->local_procedure);
2073 ns2_add_procedure(gss, sbind, SNS_PROC_ADD);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002074 break;
2075 }
2076 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002077 case NS2_SNS_EV_REQ_DELETE_BIND:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002078 sbind = data;
2079 switch (fi->state) {
2080 case GPRS_SNS_ST_UNCONFIGURED:
2081 break;
Harald Welte694dad52021-03-23 15:22:16 +01002082 case GPRS_SNS_ST_BSS_SIZE:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002083 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
2084 if (nsvc->bind == sbind->bind) {
2085 gprs_ns2_free_nsvc(nsvc);
2086 }
2087 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02002088 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002089 break;
Harald Welte694dad52021-03-23 15:22:16 +01002090 case GPRS_SNS_ST_BSS_CONFIG_BSS:
2091 case GPRS_SNS_ST_BSS_CONFIG_SGSN:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002092 case GPRS_SNS_ST_CONFIGURED:
Alexander Couzensdb07a442021-06-06 18:58:01 +02002093 case GPRS_SNS_ST_LOCAL_PROCEDURE:
2094 remove_bind_elem(gss, &gss->local_procedure, sbind);
2095 if (ip46_weight_sum(&gss->local_procedure, true) == 0 ||
2096 ip46_weight_sum(&gss->local_procedure, false) == 0) {
2097 LOGPFSML(fi, LOGL_ERROR, "NSE %d: weight has become invalid because of removing bind %s. Resetting the configuration\n",
2098 nse->nsei, sbind->bind->name);
2099 sns_failed(fi, NULL);
2100 break;
2101 }
2102 gss->block_no_nsvc_events = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002103 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
2104 if (nsvc->bind == sbind->bind) {
2105 gprs_ns2_free_nsvc(nsvc);
2106 }
2107 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02002108 gss->block_no_nsvc_events = false;
2109 if (nse->sum_sig_weight == 0 || !nse->alive || !gss->alive) {
2110 sns_failed(fi, "While deleting a bind the current state became invalid (no signalling weight)");
2111 break;
2112 }
2113
2114 /* ensure other procedures doesn't use the sbind */
2115 llist_for_each_entry(procedure, &gss->procedures, list) {
2116 if (procedure->sbind == sbind)
2117 procedure->sbind = NULL;
2118 }
2119 ns2_add_procedure(gss, sbind, SNS_PROC_DEL);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002120 break;
2121 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02002122
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002123 /* if this is the last bind, the free_nsvc() will trigger a reselection */
2124 talloc_free(sbind);
2125 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002126 case NS2_SNS_EV_REQ_CHANGE_WEIGHT:
2127 sbind = data;
2128 switch (fi->state) {
2129 case GPRS_SNS_ST_UNCONFIGURED:
2130 /* select_endpoint will check if this is a valid configuration */
2131 if (gss->role == GPRS_SNS_ROLE_BSS)
2132 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
2133 break;
2134 case GPRS_SNS_ST_BSS_SIZE:
2135 /* invalid weight? */
2136 if (!ns2_update_weight_entry(gss, sbind, &gss->local))
2137 sns_failed(fi, "updating weights results in an invalid configuration.");
2138 break;
2139 default:
2140 if (!ns2_update_weight_entry(gss, sbind, &gss->local_procedure)) {
2141 sns_failed(fi, "updating weights results in an invalid configuration.");
2142 break;
2143 }
2144 ns2_add_procedure(gss, sbind, SNS_PROC_CHANGE_WEIGHT);
2145 break;
2146 }
Alexander Couzense769f522020-12-07 07:37:07 +01002147 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002148}
2149
Alexander Couzens31d52e12021-06-05 20:04:04 +02002150/* validate the bss configuration (sns endpoint and binds)
2151 * - no endpoints -> invalid
2152 * - no binds -> invalid
2153 * - only v4 sns endpoints, only v6 binds -> invalid
2154 * - only v4 sns endpoints, but v4 sig weights == 0 -> invalid ...
2155 */
2156static int ns2_sns_bss_valid_configuration(struct ns2_sns_state *gss)
2157{
2158 struct ns2_sns_bind *sbind;
2159 struct sns_endpoint *endpoint;
2160 const struct osmo_sockaddr *addr;
2161 int v4_sig = 0, v4_data = 0, v6_sig = 0, v6_data = 0;
2162 bool v4_endpoints = false;
2163 bool v6_endpoints = false;
2164
2165 if (llist_empty(&gss->sns_endpoints) || llist_empty(&gss->binds))
2166 return 0;
2167
2168 llist_for_each_entry(sbind, &gss->binds, list) {
2169 addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
2170 if (!addr)
2171 continue;
2172 switch (addr->u.sa.sa_family) {
2173 case AF_INET:
2174 v4_sig += sbind->bind->sns_sig_weight;
2175 v4_data += sbind->bind->sns_data_weight;
2176 break;
2177 case AF_INET6:
2178 v6_sig += sbind->bind->sns_sig_weight;
2179 v6_data += sbind->bind->sns_data_weight;
2180 break;
2181 }
2182 }
2183
2184 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
2185 switch (endpoint->saddr.u.sa.sa_family) {
2186 case AF_INET:
2187 v4_endpoints = true;
2188 break;
2189 case AF_INET6:
2190 v6_endpoints = true;
2191 break;
2192 }
2193 }
2194
2195 return (v4_endpoints && v4_sig && v4_data) || (v6_endpoints && v6_sig && v6_data);
2196}
2197
Harald Welte9e37bf42021-03-02 20:48:31 +01002198/* allstate-action for BSS role */
2199static void ns2_sns_st_all_action_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2200{
2201 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2202 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2203
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002204 /* reset when receiving NS2_SNS_EV_REQ_NO_NSVC */
Harald Welte9e37bf42021-03-02 20:48:31 +01002205 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002206 case NS2_SNS_EV_REQ_NO_NSVC:
Harald Welte9e37bf42021-03-02 20:48:31 +01002207 /* ignore reselection running */
Alexander Couzensdb07a442021-06-06 18:58:01 +02002208 if (gss->reselection_running || gss->block_no_nsvc_events)
Harald Welte9e37bf42021-03-02 20:48:31 +01002209 break;
2210
Alexander Couzens652ab4d2021-06-12 23:09:46 +02002211 sns_failed(fi, "no remaining NSVC, resetting SNS FSM");
Harald Welte9e37bf42021-03-02 20:48:31 +01002212 break;
Alexander Couzens83f06ce2021-08-06 19:50:09 +02002213 case NS2_SNS_EV_REQ_FREE_NSVCS:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002214 case NS2_SNS_EV_REQ_SELECT_ENDPOINT:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002215 /* TODO: keep the order of binds when data == GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER */
Harald Welte9e37bf42021-03-02 20:48:31 +01002216 /* tear down previous state
2217 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
Alexander Couzensdb07a442021-06-06 18:58:01 +02002218 if (gss->reselection_running || gss->block_no_nsvc_events)
2219 break;
2220
Harald Welte9e37bf42021-03-02 20:48:31 +01002221 gss->reselection_running = true;
Alexander Couzensf0746592021-07-20 19:05:45 +02002222 ns2_free_nsvcs(nse);
Alexander Couzensd2c6c492021-06-06 01:57:52 +02002223 ns2_clear_elems(&gss->local);
2224 ns2_clear_elems(&gss->remote);
Harald Welte9e37bf42021-03-02 20:48:31 +01002225
2226 /* Choose the next sns endpoint. */
Alexander Couzens31d52e12021-06-05 20:04:04 +02002227 if (!ns2_sns_bss_valid_configuration(gss)) {
Harald Welte9e37bf42021-03-02 20:48:31 +01002228 gss->initial = NULL;
2229 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS);
2230 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
Alexander Couzens8a612de2021-07-20 22:15:40 +02002231 gss->reselection_running = false;
Harald Welte9e37bf42021-03-02 20:48:31 +01002232 return;
2233 } else if (!gss->initial) {
2234 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
2235 } else if (gss->initial->list.next == &gss->sns_endpoints) {
2236 /* last entry, continue with first */
2237 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
2238 } else {
2239 /* next element is an entry */
2240 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
2241 }
2242
Alexander Couzens68ab9c42021-06-06 03:03:40 +02002243 gss->family = gss->initial->saddr.u.sa.sa_family;
Harald Welte9e37bf42021-03-02 20:48:31 +01002244 gss->reselection_running = false;
Harald Welte694dad52021-03-23 15:22:16 +01002245 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Harald Welte9e37bf42021-03-02 20:48:31 +01002246 break;
2247 default:
2248 ns2_sns_st_all_action(fi, event, data);
2249 break;
2250 }
2251}
2252
Alexander Couzens6a161492020-07-12 13:45:50 +02002253static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
2254 .name = "GPRS-NS2-SNS-BSS",
2255 .states = ns2_sns_bss_states,
2256 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002257 .allstate_event_mask = S(NS2_SNS_EV_REQ_NO_NSVC) |
Alexander Couzens83f06ce2021-08-06 19:50:09 +02002258 S(NS2_SNS_EV_REQ_FREE_NSVCS) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002259 S(NS2_SNS_EV_REQ_SELECT_ENDPOINT) |
2260 S(NS2_SNS_EV_REQ_ADD_BIND) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002261 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002262 S(NS2_SNS_EV_REQ_DELETE_BIND),
Harald Welte9e37bf42021-03-02 20:48:31 +01002263 .allstate_action = ns2_sns_st_all_action_bss,
Alexander Couzens6a161492020-07-12 13:45:50 +02002264 .cleanup = NULL,
2265 .timer_cb = ns2_sns_fsm_bss_timer_cb,
Alexander Couzens6a161492020-07-12 13:45:50 +02002266 .event_names = gprs_sns_event_names,
2267 .pre_term = NULL,
2268 .log_subsys = DLNS,
2269};
2270
Harald Welte5bef2cc2020-09-18 22:33:24 +02002271/*! Allocate an IP-SNS FSM for the BSS side.
2272 * \param[in] nse NS Entity in which the FSM runs
2273 * \param[in] id string identifier
Alexander Couzens23aec352021-02-15 05:05:15 +01002274 * \returns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02002275struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
2276 const char *id)
2277{
2278 struct osmo_fsm_inst *fi;
2279 struct ns2_sns_state *gss;
2280
2281 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
2282 if (!fi)
2283 return fi;
2284
2285 gss = talloc_zero(fi, struct ns2_sns_state);
2286 if (!gss)
2287 goto err;
2288
2289 fi->priv = gss;
2290 gss->nse = nse;
Harald Welte4f127462021-03-02 20:49:10 +01002291 gss->role = GPRS_SNS_ROLE_BSS;
Harald Welte24f4df52021-03-04 18:02:54 +01002292 /* The SGSN doesn't tell the BSS, so we assume there's always sufficient */
2293 gss->num_max_ip4_remote = 8192;
2294 gss->num_max_ip6_remote = 8192;
Alexander Couzense769f522020-12-07 07:37:07 +01002295 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002296 INIT_LLIST_HEAD(&gss->binds);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002297 INIT_LLIST_HEAD(&gss->procedures);
Alexander Couzens6a161492020-07-12 13:45:50 +02002298
2299 return fi;
2300err:
2301 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
2302 return NULL;
2303}
2304
Harald Welte5bef2cc2020-09-18 22:33:24 +02002305/*! main entry point for receiving SNS messages from the network.
2306 * \param[in] nsvc NS-VC on which the message was received
2307 * \param[in] msg message buffer of the IP-SNS message
2308 * \param[in] tp parsed TLV structure of message
Alexander Couzens23aec352021-02-15 05:05:15 +01002309 * \returns 0 on success; negative on error */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002310int ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
Alexander Couzens6a161492020-07-12 13:45:50 +02002311{
2312 struct gprs_ns2_nse *nse = nsvc->nse;
2313 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
2314 uint16_t nsei = nsvc->nse->nsei;
Harald Welte4f127462021-03-02 20:49:10 +01002315 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +02002316 struct osmo_fsm_inst *fi;
Alexander Couzens7619ed42021-03-24 17:44:03 +01002317 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02002318
2319 if (!nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +01002320 LOGNSVC(nsvc, LOGL_NOTICE, "Rx %s for NS Instance that has no SNS!\n",
2321 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens7619ed42021-03-24 17:44:03 +01002322 rc = -EINVAL;
2323 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +02002324 }
2325
Alexander Couzens6a161492020-07-12 13:45:50 +02002326 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
2327 fi = nse->bss_sns_fi;
Harald Welte4f127462021-03-02 20:49:10 +01002328 gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens3178e302021-09-04 00:44:18 +02002329 gss->sns_nsvc = nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +02002330
Harald Weltef2949742021-01-20 14:54:14 +01002331 LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
2332 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
2333
Alexander Couzens6a161492020-07-12 13:45:50 +02002334 switch (nsh->pdu_type) {
2335 case SNS_PDUT_SIZE:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002336 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_SIZE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002337 break;
2338 case SNS_PDUT_SIZE_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002339 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_SIZE_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002340 break;
2341 case SNS_PDUT_CONFIG:
2342 if (nsh->data[0] & 0x01)
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002343 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG_END, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002344 else
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002345 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002346 break;
2347 case SNS_PDUT_CONFIG_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002348 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002349 break;
2350 case SNS_PDUT_ADD:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002351 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_ADD, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002352 break;
2353 case SNS_PDUT_DELETE:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002354 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_DELETE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002355 break;
2356 case SNS_PDUT_CHANGE_WEIGHT:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002357 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CHANGE_WEIGHT, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002358 break;
2359 case SNS_PDUT_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002360 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002361 break;
2362 default:
Harald Weltef2949742021-01-20 14:54:14 +01002363 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
2364 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens7619ed42021-03-24 17:44:03 +01002365 rc = -EINVAL;
Alexander Couzens6a161492020-07-12 13:45:50 +02002366 }
2367
Alexander Couzens7619ed42021-03-24 17:44:03 +01002368out:
2369 msgb_free(msg);
2370
2371 return rc;
Alexander Couzens6a161492020-07-12 13:45:50 +02002372}
2373
2374#include <osmocom/vty/vty.h>
2375#include <osmocom/vty/misc.h>
2376
Harald Welte1262c4f2021-01-19 20:58:33 +01002377static void vty_dump_sns_ip4(struct vty *vty, const char *prefix, const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +02002378{
2379 struct in_addr in = { .s_addr = ip4->ip_addr };
Harald Welte1262c4f2021-01-19 20:58:33 +01002380 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02002381 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
2382}
2383
Harald Welte1262c4f2021-01-19 20:58:33 +01002384static void vty_dump_sns_ip6(struct vty *vty, const char *prefix, const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +02002385{
2386 char ip_addr[INET6_ADDRSTRLEN] = {};
2387 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
2388 strcpy(ip_addr, "Invalid IPv6");
2389
Harald Welte1262c4f2021-01-19 20:58:33 +01002390 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02002391 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
2392}
2393
Harald Welte5bef2cc2020-09-18 22:33:24 +02002394/*! Dump the IP-SNS state to a vty.
2395 * \param[in] vty VTY to which the state shall be printed
Harald Welte1262c4f2021-01-19 20:58:33 +01002396 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte5bef2cc2020-09-18 22:33:24 +02002397 * \param[in] nse NS Entity whose IP-SNS state shall be printed
2398 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002399void ns2_sns_dump_vty(struct vty *vty, const char *prefix, const struct gprs_ns2_nse *nse, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02002400{
2401 struct ns2_sns_state *gss;
2402 unsigned int i;
2403
2404 if (!nse->bss_sns_fi)
2405 return;
2406
Harald Welte1262c4f2021-01-19 20:58:33 +01002407 vty_out_fsm_inst2(vty, prefix, nse->bss_sns_fi);
Alexander Couzens6a161492020-07-12 13:45:50 +02002408 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
2409
Harald Welte1262c4f2021-01-19 20:58:33 +01002410 vty_out(vty, "%sMaximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
2411 prefix, gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02002412
Alexander Couzens71128672021-06-05 18:44:01 +02002413 if (gss->local.num_ip4 && gss->remote.num_ip4) {
Harald Welte1262c4f2021-01-19 20:58:33 +01002414 vty_out(vty, "%sLocal IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002415 for (i = 0; i < gss->local.num_ip4; i++)
2416 vty_dump_sns_ip4(vty, prefix, &gss->local.ip4[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002417
Harald Welte1262c4f2021-01-19 20:58:33 +01002418 vty_out(vty, "%sRemote IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002419 for (i = 0; i < gss->remote.num_ip4; i++)
2420 vty_dump_sns_ip4(vty, prefix, &gss->remote.ip4[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002421 }
2422
Alexander Couzens71128672021-06-05 18:44:01 +02002423 if (gss->local.num_ip6 && gss->remote.num_ip6) {
Harald Welte1262c4f2021-01-19 20:58:33 +01002424 vty_out(vty, "%sLocal IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002425 for (i = 0; i < gss->local.num_ip6; i++)
2426 vty_dump_sns_ip6(vty, prefix, &gss->local.ip6[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002427
Harald Welte1262c4f2021-01-19 20:58:33 +01002428 vty_out(vty, "%sRemote IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002429 for (i = 0; i < gss->remote.num_ip6; i++)
2430 vty_dump_sns_ip6(vty, prefix, &gss->remote.ip6[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002431 }
2432}
2433
Alexander Couzens412bc342020-11-19 05:24:37 +01002434/*! write IP-SNS to a vty
2435 * \param[in] vty VTY to which the state shall be printed
2436 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002437void ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
Alexander Couzens412bc342020-11-19 05:24:37 +01002438{
2439 struct ns2_sns_state *gss;
2440 struct osmo_sockaddr_str addr_str;
2441 struct sns_endpoint *endpoint;
2442
2443 if (!nse->bss_sns_fi)
2444 return;
2445
2446 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
2447 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01002448 /* It's unlikely that an error happens, but let's better be safe. */
2449 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
2450 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002451 vty_out(vty, " ip-sns-remote %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
Alexander Couzens412bc342020-11-19 05:24:37 +01002452 }
2453}
2454
Alexander Couzense769f522020-12-07 07:37:07 +01002455static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
2456 const struct osmo_sockaddr *saddr)
2457{
2458 struct sns_endpoint *endpoint;
2459
2460 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
2461 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
2462 return endpoint;
2463 }
2464
2465 return NULL;
2466}
2467
2468/*! gprs_ns2_sns_add_endpoint
2469 * \param[in] nse
2470 * \param[in] sockaddr
2471 * \return
2472 */
2473int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
2474 const struct osmo_sockaddr *saddr)
2475{
2476 struct ns2_sns_state *gss;
2477 struct sns_endpoint *endpoint;
2478 bool do_selection = false;
2479
2480 if (nse->ll != GPRS_NS2_LL_UDP) {
2481 return -EINVAL;
2482 }
2483
Alexander Couzens138b96f2021-01-25 16:23:29 +01002484 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002485 return -EINVAL;
2486 }
2487
2488 gss = nse->bss_sns_fi->priv;
2489
2490 if (ns2_get_sns_endpoint(gss, saddr))
2491 return -EADDRINUSE;
2492
2493 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
2494 if (!endpoint)
2495 return -ENOMEM;
2496
2497 endpoint->saddr = *saddr;
2498 if (llist_empty(&gss->sns_endpoints))
2499 do_selection = true;
2500
2501 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
2502 if (do_selection)
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002503 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01002504
2505 return 0;
2506}
2507
2508/*! gprs_ns2_sns_del_endpoint
2509 * \param[in] nse
2510 * \param[in] sockaddr
2511 * \return 0 on success, otherwise < 0
2512 */
2513int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
2514 const struct osmo_sockaddr *saddr)
2515{
2516 struct ns2_sns_state *gss;
2517 struct sns_endpoint *endpoint;
2518
2519 if (nse->ll != GPRS_NS2_LL_UDP) {
2520 return -EINVAL;
2521 }
2522
Alexander Couzens138b96f2021-01-25 16:23:29 +01002523 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002524 return -EINVAL;
2525 }
2526
2527 gss = nse->bss_sns_fi->priv;
2528 endpoint = ns2_get_sns_endpoint(gss, saddr);
2529 if (!endpoint)
2530 return -ENOENT;
2531
2532 /* if this is an unused SNS endpoint it's done */
2533 if (gss->initial != endpoint) {
2534 llist_del(&endpoint->list);
2535 talloc_free(endpoint);
2536 return 0;
2537 }
2538
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002539 /* gprs_ns2_free_nsvcs() will trigger NS2_SNS_EV_REQ_NO_NSVC on the last NS-VC
Alexander Couzense769f522020-12-07 07:37:07 +01002540 * and restart SNS SIZE procedure which selects a new initial */
Harald Weltef2949742021-01-20 14:54:14 +01002541 LOGNSE(nse, LOGL_INFO, "Current in-use SNS endpoint is being removed."
Alexander Couzense769f522020-12-07 07:37:07 +01002542 "Closing all NS-VC and restart SNS-SIZE procedure"
2543 "with a remaining SNS endpoint.\n");
2544
2545 /* Continue with the next endpoint in the list.
2546 * Special case if the endpoint is at the start or end of the list */
2547 if (endpoint->list.prev == &gss->sns_endpoints ||
2548 endpoint->list.next == &gss->sns_endpoints)
2549 gss->initial = NULL;
2550 else
2551 gss->initial = llist_entry(endpoint->list.next->prev,
2552 struct sns_endpoint,
2553 list);
2554
2555 llist_del(&endpoint->list);
2556 gprs_ns2_free_nsvcs(nse);
2557 talloc_free(endpoint);
2558
2559 return 0;
2560}
2561
2562/*! gprs_ns2_sns_count
2563 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
2564 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
2565 */
2566int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
2567{
2568 struct ns2_sns_state *gss;
2569 struct sns_endpoint *endpoint;
2570 int count = 0;
2571
2572 if (nse->ll != GPRS_NS2_LL_UDP) {
2573 return -EINVAL;
2574 }
2575
Alexander Couzens138b96f2021-01-25 16:23:29 +01002576 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002577 return -EINVAL;
2578 }
2579
2580 gss = nse->bss_sns_fi->priv;
2581 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
2582 count++;
2583
2584 return count;
2585}
2586
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002587void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive)
2588{
2589 struct ns2_sns_state *gss;
2590 struct gprs_ns2_vc *tmp;
2591
2592 if (!nse->bss_sns_fi)
2593 return;
2594
2595 gss = nse->bss_sns_fi->priv;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002596 if (nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED && nse->bss_sns_fi->state != GPRS_SNS_ST_LOCAL_PROCEDURE)
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002597 return;
2598
Alexander Couzensdb07a442021-06-06 18:58:01 +02002599 if (gss->block_no_nsvc_events)
2600 return;
2601
Alexander Couzens1adfd232021-07-20 22:16:09 +02002602 if (gss->alive && nse->sum_sig_weight == 0) {
2603 sns_failed(nse->bss_sns_fi, "No signalling NSVC available");
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002604 return;
Alexander Couzens1adfd232021-07-20 22:16:09 +02002605 }
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002606
2607 /* check if this is the current SNS NS-VC */
Alexander Couzens1adfd232021-07-20 22:16:09 +02002608 if (nsvc == gss->sns_nsvc && !alive) {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002609 /* only replace the SNS NS-VC if there are other alive NS-VC.
2610 * There aren't any other alive NS-VC when the SNS fsm just reached CONFIGURED
2611 * and couldn't confirm yet if the NS-VC comes up */
Alexander Couzens1adfd232021-07-20 22:16:09 +02002612 llist_for_each_entry(tmp, &nse->nsvc, list) {
2613 if (nsvc == tmp)
2614 continue;
2615 if (ns2_vc_is_unblocked(nsvc)) {
2616 ns2_sns_replace_nsvc(nsvc);
2617 break;
2618 }
2619 }
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002620 }
2621
Alexander Couzens1adfd232021-07-20 22:16:09 +02002622 if (alive == gss->alive)
2623 return;
2624
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002625 if (alive) {
Alexander Couzens1adfd232021-07-20 22:16:09 +02002626 /* we need at least a signalling NSVC before become alive */
2627 if (nse->sum_sig_weight == 0)
2628 return;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002629 gss->alive = true;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002630 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_NSVC_ALIVE, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002631 } else {
2632 /* is there at least another alive nsvc? */
2633 llist_for_each_entry(tmp, &nse->nsvc, list) {
2634 if (ns2_vc_is_unblocked(tmp))
2635 return;
2636 }
2637
2638 /* all NS-VC have failed */
2639 gss->alive = false;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002640 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_NO_NSVC, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002641 }
2642}
2643
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002644int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse,
2645 struct gprs_ns2_vc_bind *bind)
2646{
2647 struct ns2_sns_state *gss;
2648 struct ns2_sns_bind *tmp;
2649
2650 OSMO_ASSERT(nse->bss_sns_fi);
2651 gss = nse->bss_sns_fi->priv;
2652
2653 if (!gprs_ns2_is_ip_bind(bind)) {
2654 return -EINVAL;
2655 }
2656
2657 if (!llist_empty(&gss->binds)) {
2658 llist_for_each_entry(tmp, &gss->binds, list) {
2659 if (tmp->bind == bind)
2660 return -EALREADY;
2661 }
2662 }
2663
2664 tmp = talloc_zero(gss, struct ns2_sns_bind);
2665 if (!tmp)
2666 return -ENOMEM;
2667 tmp->bind = bind;
2668 llist_add_tail(&tmp->list, &gss->binds);
2669
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002670 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_ADD_BIND, tmp);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002671 return 0;
2672}
2673
2674/* Remove a bind from the SNS. All assosiated NSVC must be removed. */
2675int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse,
2676 struct gprs_ns2_vc_bind *bind)
2677{
2678 struct ns2_sns_state *gss;
2679 struct ns2_sns_bind *tmp, *tmp2;
2680 bool found = false;
2681
2682 if (!nse->bss_sns_fi)
2683 return -EINVAL;
2684
2685 gss = nse->bss_sns_fi->priv;
2686 if (gss->initial_bind && gss->initial_bind->bind == bind) {
2687 if (gss->initial_bind->list.prev == &gss->binds)
2688 gss->initial_bind = NULL;
2689 else
2690 gss->initial_bind = llist_entry(gss->initial_bind->list.prev, struct ns2_sns_bind, list);
2691 }
2692
2693 llist_for_each_entry_safe(tmp, tmp2, &gss->binds, list) {
2694 if (tmp->bind == bind) {
2695 llist_del(&tmp->list);
2696 found = true;
Alexander Couzensa35c2962021-04-19 03:30:15 +02002697 break;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002698 }
2699 }
2700
2701 if (!found)
2702 return -ENOENT;
2703
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002704 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_DELETE_BIND, tmp);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002705 return 0;
2706}
2707
Alexander Couzens71128672021-06-05 18:44:01 +02002708/* Update SNS weights for a bind (local endpoint).
2709 * \param[in] bind the bind which has been updated
Alexander Couzensc4704762021-02-08 23:13:12 +01002710 */
2711void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)
2712{
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002713 struct ns2_sns_bind *sbind;
2714 struct gprs_ns2_nse *nse;
2715 struct ns2_sns_state *gss;
2716 const struct osmo_sockaddr *addr = gprs_ns2_ip_bind_sockaddr(bind);
2717
2718 llist_for_each_entry(nse, &bind->nsi->nse, list) {
2719 if (!nse->bss_sns_fi)
2720 continue;
2721
2722 gss = nse->bss_sns_fi->priv;
2723 if (addr->u.sa.sa_family != gss->family)
2724 return;
2725
2726 llist_for_each_entry(sbind, &gss->binds, list) {
2727 if (sbind->bind == bind) {
2728 osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, NS2_SNS_EV_REQ_CHANGE_WEIGHT, sbind);
2729 break;
2730 }
2731 }
2732 }
Alexander Couzensc4704762021-02-08 23:13:12 +01002733}
2734
Harald Welte4f127462021-03-02 20:49:10 +01002735
2736
2737
2738/***********************************************************************
2739 * SGSN role
2740 ***********************************************************************/
2741
Alexander Couzensa2707822021-07-20 18:59:40 +02002742/* cleanup all state. If nsvc is given, don't remove this nsvc. (nsvc is given when a SIZE PDU received) */
2743static void ns2_clear_sgsn(struct ns2_sns_state *gss, struct gprs_ns2_vc *size_nsvc)
2744{
2745 struct gprs_ns2_vc *nsvc, *nsvc2;
2746
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002747 ns2_clear_procedures(gss);
Alexander Couzensa2707822021-07-20 18:59:40 +02002748 ns2_clear_elems(&gss->local);
2749 ns2_clear_elems(&gss->remote);
Alexander Couzensc2fec692021-09-04 01:10:46 +02002750 gss->block_no_nsvc_events = true;
Alexander Couzensa2707822021-07-20 18:59:40 +02002751 llist_for_each_entry_safe(nsvc, nsvc2, &gss->nse->nsvc, list) {
2752 /* Ignore the NSVC over which the SIZE PDU got received */
2753 if (size_nsvc && size_nsvc == nsvc)
2754 continue;
2755
2756 gprs_ns2_free_nsvc(nsvc);
2757 }
Alexander Couzensc2fec692021-09-04 01:10:46 +02002758 gss->block_no_nsvc_events = false;
Alexander Couzensa2707822021-07-20 18:59:40 +02002759}
2760
2761static void ns2_sns_st_sgsn_unconfigured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
2762{
2763 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2764
2765 ns2_clear_sgsn(gss, NULL);
2766}
2767
Harald Welte4f127462021-03-02 20:49:10 +01002768static void ns2_sns_st_sgsn_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2769{
2770 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2771 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2772 /* do nothing; Rx SNS-SIZE handled in ns2_sns_st_all_action_sgsn() */
2773}
2774
2775/* We're waiting for inbound SNS-CONFIG from the BSS */
2776static void ns2_sns_st_sgsn_wait_config(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2777{
2778 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2779 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2780 struct gprs_ns2_inst *nsi = nse->nsi;
2781 uint8_t cause;
2782 int rc;
2783
2784 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2785
2786 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002787 case NS2_SNS_EV_RX_CONFIG:
2788 case NS2_SNS_EV_RX_CONFIG_END:
Harald Welte4f127462021-03-02 20:49:10 +01002789 rc = ns_sns_append_remote_eps(fi, data);
2790 if (rc < 0) {
2791 cause = -rc;
2792 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
2793 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2794 return;
2795 }
2796 /* only change state if last CONFIG was received */
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002797 if (event == NS2_SNS_EV_RX_CONFIG_END) {
Harald Welte4f127462021-03-02 20:49:10 +01002798 /* ensure sum of data weight / sig weights is > 0 */
Alexander Couzens019da4b2021-06-06 02:48:18 +02002799 if (ip46_weight_sum_data(&gss->remote) == 0 || ip46_weight_sum_sig(&gss->remote) == 0) {
Harald Welte4f127462021-03-02 20:49:10 +01002800 cause = NS_CAUSE_INVAL_WEIGH;
2801 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
2802 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2803 break;
2804 }
2805 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
2806 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2807 } else {
2808 /* just send CONFIG-ACK */
2809 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
2810 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
2811 }
2812 break;
2813 }
2814}
2815
2816static void ns2_sns_st_sgsn_wait_config_ack_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
2817{
2818 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2819 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2820
Harald Welte4f127462021-03-02 20:49:10 +01002821 /* transmit SGSN-oriented SNS-CONFIG */
Alexander Couzens71128672021-06-05 18:44:01 +02002822 ns2_tx_sns_config(gss->sns_nsvc, true, gss->local.ip4, gss->local.num_ip4,
2823 gss->local.ip6, gss->local.num_ip6);
Harald Welte4f127462021-03-02 20:49:10 +01002824}
2825
2826/* We're waiting for SNS-CONFIG-ACK from the BSS (in response to our outbound SNS-CONFIG) */
2827static void ns2_sns_st_sgsn_wait_config_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2828{
2829 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2830 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2831 struct tlv_parsed *tp = NULL;
2832
2833 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2834
2835 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002836 case NS2_SNS_EV_RX_CONFIG_ACK:
Harald Welte4f127462021-03-02 20:49:10 +01002837 tp = data;
2838 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
2839 LOGPFSML(fi, LOGL_ERROR, "Rx SNS-CONFIG-ACK with cause %s\n",
2840 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
2841 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2842 break;
2843 }
2844 /* we currently only send one SNS-CONFIG with END FLAG */
2845 if (true) {
2846 create_missing_nsvcs(fi);
2847 /* start the test procedure on ALL NSVCs! */
2848 gprs_ns2_start_alive_all_nsvcs(nse);
2849 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, ns_sns_configured_timeout(fi), 4);
2850 }
2851 break;
2852 }
2853}
2854
2855/* SGSN-side SNS state machine */
2856static const struct osmo_fsm_state ns2_sns_sgsn_states[] = {
2857 [GPRS_SNS_ST_UNCONFIGURED] = {
2858 .in_event_mask = 0, /* handled by all_state_action */
2859 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2860 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG),
2861 .name = "UNCONFIGURED",
2862 .action = ns2_sns_st_sgsn_unconfigured,
Alexander Couzensa2707822021-07-20 18:59:40 +02002863 .onenter = ns2_sns_st_sgsn_unconfigured_onenter,
Harald Welte4f127462021-03-02 20:49:10 +01002864 },
2865 [GPRS_SNS_ST_SGSN_WAIT_CONFIG] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002866 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG) |
2867 S(NS2_SNS_EV_RX_CONFIG_END),
Harald Welte4f127462021-03-02 20:49:10 +01002868 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2869 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
2870 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK),
2871 .name = "SGSN_WAIT_CONFIG",
2872 .action = ns2_sns_st_sgsn_wait_config,
2873 },
2874 [GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002875 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG_ACK),
Harald Welte4f127462021-03-02 20:49:10 +01002876 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzensa2707822021-07-20 18:59:40 +02002877 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
Harald Welte4f127462021-03-02 20:49:10 +01002878 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK) |
2879 S(GPRS_SNS_ST_CONFIGURED),
2880 .name = "SGSN_WAIT_CONFIG_ACK",
2881 .action = ns2_sns_st_sgsn_wait_config_ack,
2882 .onenter = ns2_sns_st_sgsn_wait_config_ack_onenter,
2883 },
2884 [GPRS_SNS_ST_CONFIGURED] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002885 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
2886 S(NS2_SNS_EV_RX_DELETE) |
2887 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
2888 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
Alexander Couzensa2707822021-07-20 18:59:40 +02002889 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002890 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
2891 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
Harald Welte4f127462021-03-02 20:49:10 +01002892 .name = "CONFIGURED",
2893 /* shared with BSS side; once configured there's no difference */
2894 .action = ns2_sns_st_configured,
2895 .onenter = ns2_sns_st_configured_onenter,
2896 },
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002897 [GPRS_SNS_ST_LOCAL_PROCEDURE] = {
2898 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
2899 S(NS2_SNS_EV_RX_DELETE) |
2900 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
2901 S(NS2_SNS_EV_RX_ACK) |
2902 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
2903 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
2904 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2905 S(GPRS_SNS_ST_CONFIGURED) |
2906 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
2907 .name = "LOCAL_PROCEDURE",
2908 /* shared with BSS side; once configured there's no difference */
2909 .action = ns2_sns_st_local_procedure,
2910 .onenter = ns2_sns_st_local_procedure_onenter,
2911 },
Harald Welte4f127462021-03-02 20:49:10 +01002912};
2913
2914static int ns2_sns_fsm_sgsn_timer_cb(struct osmo_fsm_inst *fi)
2915{
2916 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2917 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2918 struct gprs_ns2_inst *nsi = nse->nsi;
2919
2920 gss->N++;
2921 switch (fi->T) {
2922 case 3:
2923 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
2924 LOGPFSML(fi, LOGL_ERROR, "NSE %d: SGSN Config retries failed. Giving up.\n", nse->nsei);
2925 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2926 } else {
2927 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2928 }
2929 break;
2930 case 4:
2931 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online.\n", nse->nsei);
2932 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002933 case 5:
2934 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES]) {
2935 sns_failed(fi, "SNS Procedure retries failed.");
2936 } else {
2937 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV],
2938 fi->T);
2939 }
2940 break;
Harald Welte4f127462021-03-02 20:49:10 +01002941 }
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002942
Harald Welte4f127462021-03-02 20:49:10 +01002943 return 0;
2944}
2945
Harald Welte4f127462021-03-02 20:49:10 +01002946/* allstate-action for SGSN role */
2947static void ns2_sns_st_all_action_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2948{
2949 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2950 struct tlv_parsed *tp = NULL;
Harald Welte01fa6a32021-03-04 19:49:38 +01002951 size_t num_local_eps, num_remote_eps;
Harald Welte4f127462021-03-02 20:49:10 +01002952 uint8_t flag;
Harald Weltea2c5af52021-03-04 17:59:35 +01002953 uint8_t cause;
Harald Welte4f127462021-03-02 20:49:10 +01002954
2955 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2956
2957 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002958 case NS2_SNS_EV_RX_SIZE:
Harald Welte4f127462021-03-02 20:49:10 +01002959 tp = (struct tlv_parsed *) data;
Harald Weltea2c5af52021-03-04 17:59:35 +01002960 /* check for mandatory / conditional IEs */
2961 if (!TLVP_PRES_LEN(tp, NS_IE_RESET_FLAG, 1) ||
2962 !TLVP_PRES_LEN(tp, NS_IE_MAX_NR_NSVC, 2)) {
2963 cause = NS_CAUSE_MISSING_ESSENT_IE;
2964 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002965 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2966 sns_failed(fi, "Rx Size: Missing essential IE");
Harald Weltea2c5af52021-03-04 17:59:35 +01002967 break;
2968 }
2969 if (!TLVP_PRES_LEN(tp, NS_IE_IPv4_EP_NR, 2) &&
2970 !TLVP_PRES_LEN(tp, NS_IE_IPv6_EP_NR, 2)) {
2971 cause = NS_CAUSE_MISSING_ESSENT_IE;
Harald Welte4f127462021-03-02 20:49:10 +01002972 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002973 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2974 sns_failed(fi, "Rx Size: Missing essential IE");
Harald Welte4f127462021-03-02 20:49:10 +01002975 break;
2976 }
Harald Welte01fa6a32021-03-04 19:49:38 +01002977 if (TLVP_PRES_LEN(tp, NS_IE_IPv4_EP_NR, 2))
2978 gss->num_max_ip4_remote = tlvp_val16be(tp, NS_IE_IPv4_EP_NR);
2979 if (TLVP_PRES_LEN(tp, NS_IE_IPv6_EP_NR, 2))
2980 gss->num_max_ip6_remote = tlvp_val16be(tp, NS_IE_IPv6_EP_NR);
2981 /* decide if we go for IPv4 or IPv6 */
Alexander Couzens077ce5a2021-06-06 01:32:45 +02002982 if (gss->num_max_ip6_remote && ns2_sns_count_num_local_ep(fi, AF_INET6)) {
2983 gss->family = AF_INET6;
Harald Welte2d807b62021-03-24 01:57:30 +01002984 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens71128672021-06-05 18:44:01 +02002985 num_local_eps = gss->local.num_ip6;
Harald Welte01fa6a32021-03-04 19:49:38 +01002986 num_remote_eps = gss->num_max_ip6_remote;
Alexander Couzens077ce5a2021-06-06 01:32:45 +02002987 } else if (gss->num_max_ip4_remote && ns2_sns_count_num_local_ep(fi, AF_INET)) {
2988 gss->family = AF_INET;
Harald Welte2d807b62021-03-24 01:57:30 +01002989 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens71128672021-06-05 18:44:01 +02002990 num_local_eps = gss->local.num_ip4;
Harald Welte01fa6a32021-03-04 19:49:38 +01002991 num_remote_eps = gss->num_max_ip4_remote;
2992 } else {
Alexander Couzens71128672021-06-05 18:44:01 +02002993 if (gss->local.num_ip4 && !gss->num_max_ip4_remote)
Harald Welte01fa6a32021-03-04 19:49:38 +01002994 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
2995 else
2996 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
2997 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002998 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2999 sns_failed(fi, "Rx Size: Invalid Nr of IPv4/IPv6 EPs");
Harald Welte01fa6a32021-03-04 19:49:38 +01003000 break;
3001 }
Harald Welte01fa6a32021-03-04 19:49:38 +01003002 /* ensure number of NS-VCs is sufficient for full mesh */
3003 gss->num_max_nsvcs = tlvp_val16be(tp, NS_IE_MAX_NR_NSVC);
3004 if (gss->num_max_nsvcs < num_remote_eps * num_local_eps) {
3005 LOGPFSML(fi, LOGL_ERROR, "%zu local and %zu remote EPs, requires %zu NS-VC, "
3006 "but BSS supports only %zu maximum NS-VCs\n", num_local_eps,
3007 num_remote_eps, num_local_eps * num_remote_eps, gss->num_max_nsvcs);
3008 cause = NS_CAUSE_INVAL_NR_NS_VC;
3009 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02003010 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
3011 sns_failed(fi, NULL);
Harald Welte01fa6a32021-03-04 19:49:38 +01003012 break;
3013 }
3014 /* perform state reset, if requested */
Harald Welte4f127462021-03-02 20:49:10 +01003015 flag = *TLVP_VAL(tp, NS_IE_RESET_FLAG);
3016 if (flag & 1) {
Harald Welte4f127462021-03-02 20:49:10 +01003017 /* clear all state */
Alexander Couzensa2707822021-07-20 18:59:40 +02003018 /* TODO: ensure gss->sns_nsvc is always the NSVC on which we received the SIZE PDU */
Harald Welte4f127462021-03-02 20:49:10 +01003019 gss->N = 0;
Alexander Couzensa2707822021-07-20 18:59:40 +02003020 ns2_clear_sgsn(gss, gss->sns_nsvc);
3021 /* keep the NSVC we need for SNS, but unconfigure it */
3022 gss->sns_nsvc->sig_weight = 0;
3023 gss->sns_nsvc->data_weight = 0;
Alexander Couzens9cd9f6d2021-09-06 17:47:16 +02003024 gss->block_no_nsvc_events = true;
Alexander Couzensa2707822021-07-20 18:59:40 +02003025 ns2_vc_force_unconfigured(gss->sns_nsvc);
Alexander Couzens9cd9f6d2021-09-06 17:47:16 +02003026 gss->block_no_nsvc_events = false;
Harald Welte2d807b62021-03-24 01:57:30 +01003027 ns2_sns_compute_local_ep_from_binds(fi);
Harald Welte4f127462021-03-02 20:49:10 +01003028 }
Alexander Couzens1c405252021-06-13 00:14:48 +02003029
3030 if (fi->state == GPRS_SNS_ST_UNCONFIGURED && !(flag & 1)) {
3031 sns_failed(fi, "Rx Size without Reset flag, but NSE is unknown");
3032 break;
3033 }
3034
Harald Welte4f127462021-03-02 20:49:10 +01003035 /* send SIZE_ACK */
3036 ns2_tx_sns_size_ack(gss->sns_nsvc, NULL);
3037 /* only wait for SNS-CONFIG in case of Reset flag */
3038 if (flag & 1)
3039 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG, 0, 0);
3040 break;
Alexander Couzens83f06ce2021-08-06 19:50:09 +02003041 case NS2_SNS_EV_REQ_FREE_NSVCS:
3042 sns_failed(fi, "On user request to free all NSVCs");
3043 break;
Harald Welte4f127462021-03-02 20:49:10 +01003044 default:
3045 ns2_sns_st_all_action(fi, event, data);
3046 break;
3047 }
3048}
3049
3050static struct osmo_fsm gprs_ns2_sns_sgsn_fsm = {
3051 .name = "GPRS-NS2-SNS-SGSN",
3052 .states = ns2_sns_sgsn_states,
3053 .num_states = ARRAY_SIZE(ns2_sns_sgsn_states),
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003054 .allstate_event_mask = S(NS2_SNS_EV_RX_SIZE) |
3055 S(NS2_SNS_EV_REQ_NO_NSVC) |
Alexander Couzens83f06ce2021-08-06 19:50:09 +02003056 S(NS2_SNS_EV_REQ_FREE_NSVCS) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003057 S(NS2_SNS_EV_REQ_ADD_BIND) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02003058 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003059 S(NS2_SNS_EV_REQ_DELETE_BIND),
Harald Welte4f127462021-03-02 20:49:10 +01003060 .allstate_action = ns2_sns_st_all_action_sgsn,
3061 .cleanup = NULL,
3062 .timer_cb = ns2_sns_fsm_sgsn_timer_cb,
3063 .event_names = gprs_sns_event_names,
3064 .pre_term = NULL,
3065 .log_subsys = DLNS,
3066};
3067
3068/*! Allocate an IP-SNS FSM for the SGSN side.
3069 * \param[in] nse NS Entity in which the FSM runs
3070 * \param[in] id string identifier
3071 * \returns FSM instance on success; NULL on error */
3072struct osmo_fsm_inst *ns2_sns_sgsn_fsm_alloc(struct gprs_ns2_nse *nse, const char *id)
3073{
3074 struct osmo_fsm_inst *fi;
3075 struct ns2_sns_state *gss;
3076
3077 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_sgsn_fsm, nse, NULL, LOGL_DEBUG, id);
3078 if (!fi)
3079 return fi;
3080
3081 gss = talloc_zero(fi, struct ns2_sns_state);
3082 if (!gss)
3083 goto err;
3084
3085 fi->priv = gss;
3086 gss->nse = nse;
3087 gss->role = GPRS_SNS_ROLE_SGSN;
3088 INIT_LLIST_HEAD(&gss->sns_endpoints);
3089 INIT_LLIST_HEAD(&gss->binds);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02003090 INIT_LLIST_HEAD(&gss->procedures);
Harald Welte4f127462021-03-02 20:49:10 +01003091
3092 return fi;
3093err:
3094 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
3095 return NULL;
3096}
3097
3098
3099
3100
Alexander Couzens6a161492020-07-12 13:45:50 +02003101/* initialize osmo_ctx on main tread */
3102static __attribute__((constructor)) void on_dso_load_ctx(void)
3103{
3104 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
Harald Welte4f127462021-03-02 20:49:10 +01003105 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_sgsn_fsm) == 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02003106}