blob: 69a58d4a39cc5c28034a418431772684dfed77c5 [file] [log] [blame]
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001/* NS-over-IP proxy */
2
Harald Weltee5209642020-12-05 19:59:45 +01003/* (C) 2010-2020 by Harald Welte <laforge@gnumonks.org>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02004 * (C) 2010-2013 by On-Waves
5 * (C) 2013 by Holger Hans Peter Freyther
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <unistd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <errno.h>
29#include <sys/fcntl.h>
30#include <sys/stat.h>
31#include <arpa/inet.h>
32#include <time.h>
33
Harald Welted2fef952020-12-05 00:31:07 +010034#include <osmocom/core/hashtable.h>
Daniel Willmann8f407b12020-12-02 19:33:50 +010035#include <osmocom/core/logging.h>
Daniel Willmannee834af2020-12-14 16:22:39 +010036#include <osmocom/core/linuxlist.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020037#include <osmocom/core/talloc.h>
38#include <osmocom/core/select.h>
39#include <osmocom/core/rate_ctr.h>
Daniel Willmann1ac920b2021-02-11 23:51:49 +010040#include <osmocom/core/signal.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020041#include <osmocom/core/stats.h>
Daniel Willmannd4ab1f92020-12-21 18:53:55 +010042#include <osmocom/core/utils.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020043
Alexander Couzens951e1332020-09-22 13:21:46 +020044#include <osmocom/gprs/gprs_ns2.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020045#include <osmocom/gprs/gprs_bssgp.h>
Harald Welte209dc9f2020-12-12 19:02:16 +010046#include <osmocom/gprs/gprs_bssgp2.h>
Alexander Couzens951e1332020-09-22 13:21:46 +020047#include <osmocom/gprs/gprs_bssgp_bss.h>
Harald Weltee5209642020-12-05 19:59:45 +010048#include <osmocom/gprs/bssgp_bvc_fsm.h>
Philipp Maier1c5766b2021-02-09 17:03:03 +010049#include <osmocom/gprs/protocol/gsm_08_18.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020050
Daniel Willmannd4ab1f92020-12-21 18:53:55 +010051#include <osmocom/gsm/gsm23236.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020052#include <osmocom/gsm/gsm_utils.h>
53
Oliver Smith29532c22021-01-29 11:13:00 +010054#include "debug.h"
Daniel Willmanna16ecc32021-03-10 09:57:12 +010055#include <osmocom/gbproxy/gb_proxy.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020056
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020057#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020058
59extern void *tall_sgsn_ctx;
60
61static const struct rate_ctr_desc global_ctr_description[] = {
Daniel Willmann99a46ff2021-09-27 15:39:44 +020062 [GBPROX_GLOB_CTR_INV_BVCI] = { "inv-bvci", "Invalid BVC Identifier " },
63 [GBPROX_GLOB_CTR_INV_LAI] = { "inv-lai", "Invalid Location Area Identifier" },
64 [GBPROX_GLOB_CTR_INV_RAI] = { "inv-rai", "Invalid Routing Area Identifier " },
65 [GBPROX_GLOB_CTR_INV_NSEI] = { "inv-nsei", "No BVC established for NSEI " },
66 [GBPROX_GLOB_CTR_PROTO_ERR_BSS] = { "proto-err:bss", "BSSGP protocol error (BSS )" },
67 [GBPROX_GLOB_CTR_PROTO_ERR_SGSN] = { "proto-err:sgsn", "BSSGP protocol error (SGSN)" },
68 [GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS] = { "not-supp:bss", "Feature not supported (BSS )" },
69 [GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN] = { "not-supp:sgsn", "Feature not supported (SGSN)" },
70 [GBPROX_GLOB_CTR_RESTART_RESET_SGSN] = { "restart:sgsn", "Restarted RESET procedure (SGSN)" },
71 [GBPROX_GLOB_CTR_TX_ERR_SGSN] = { "tx-err:sgsn", "NS Transmission error (SGSN)" },
72 [GBPROX_GLOB_CTR_OTHER_ERR] = { "error", "Other error " },
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020073};
74
75static const struct rate_ctr_group_desc global_ctrg_desc = {
76 .group_name_prefix = "gbproxy:global",
77 .group_description = "GBProxy Global Statistics",
78 .num_ctr = ARRAY_SIZE(global_ctr_description),
79 .ctr_desc = global_ctr_description,
80 .class_id = OSMO_STATS_CLASS_GLOBAL,
81};
82
Harald Welte560bdb32020-12-04 22:24:47 +010083static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,
Daniel Willmann35f7d332020-11-03 21:11:45 +010084 uint16_t ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020085
Daniel Willmannf8cba652021-02-12 04:59:47 +010086int tx_status(struct gbproxy_nse *nse, uint16_t ns_bvci, enum gprs_bssgp_cause cause, const uint16_t *bvci, const struct msgb *old_msg)
87{
88 int rc;
Harald Weltea0f70732020-12-05 17:50:23 +010089
Daniel Willmannf8cba652021-02-12 04:59:47 +010090 struct msgb *msg = bssgp2_enc_status(cause, bvci, old_msg, nse->max_sdu_len);
91 if (!msg) {
92 LOGPNSE(nse, LOGL_NOTICE, "Unable to encode STATUS message\n");
93 return -ENOMEM;
94 }
95
96 rc = bssgp2_nsi_tx_ptp(nse->cfg->nsi, nse->nsei, ns_bvci, msg, 0);
97 if (rc < 0)
98 LOGPNSE(nse, LOGL_NOTICE, "Unable to send STATUS message\n");
99 return rc;
100}
101
102/* generate BVC-STATUS mess
103age with cause value derived from TLV-parser error */
104static int tx_status_from_tlvp(struct gbproxy_nse *nse, enum osmo_tlv_parser_error tlv_p_err, struct msgb *orig_msg)
Harald Welteec0f8012020-12-06 16:32:01 +0100105{
106 uint8_t bssgp_cause;
107 switch (tlv_p_err) {
108 case OSMO_TLVP_ERR_MAND_IE_MISSING:
109 bssgp_cause = BSSGP_CAUSE_MISSING_MAND_IE;
110 break;
111 default:
112 bssgp_cause = BSSGP_CAUSE_PROTO_ERR_UNSPEC;
113 }
Daniel Willmannf8cba652021-02-12 04:59:47 +0100114 return tx_status(nse, msgb_bvci(orig_msg), bssgp_cause, NULL, orig_msg);
Harald Welteec0f8012020-12-06 16:32:01 +0100115}
116
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200117/* strip off the NS header */
118static void strip_ns_hdr(struct msgb *msg)
119{
120 int strip_len = msgb_bssgph(msg) - msg->data;
121 msgb_pull(msg, strip_len);
122}
123
Harald Weltee5209642020-12-05 19:59:45 +0100124#if 0
Harald Welte560bdb32020-12-04 22:24:47 +0100125/* feed a message down the NS-VC associated with the specified bvc */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200126static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
127 uint16_t ns_bvci, uint16_t sgsn_nsei)
128{
129 /* create a copy of the message so the old one can
130 * be free()d safely when we return from gbprox_rcvmsg() */
Alexander Couzens951e1332020-09-22 13:21:46 +0200131 struct gprs_ns2_inst *nsi = cfg->nsi;
132 struct osmo_gprs_ns2_prim nsp = {};
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200133 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2sgsn");
134 int rc;
135
Daniel Willmann3696dce2020-12-02 16:08:02 +0100136 DEBUGP(DGPRS, "NSE(%05u/BSS)-BVC(%05u) proxying BTS->SGSN NSE(%05u/SGSN)\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200137 msgb_nsei(msg), ns_bvci, sgsn_nsei);
138
Alexander Couzens951e1332020-09-22 13:21:46 +0200139 nsp.bvci = ns_bvci;
140 nsp.nsei = sgsn_nsei;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200141
142 strip_ns_hdr(msg);
Alexander Couzens951e1332020-09-22 13:21:46 +0200143 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA,
144 PRIM_OP_REQUEST, msg);
145 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200146 if (rc < 0)
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200147 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_TX_ERR_SGSN));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200148 return rc;
149}
Harald Weltee5209642020-12-05 19:59:45 +0100150#endif
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200151
Harald Weltee30985e2021-01-28 19:13:19 +0100152/*! Determine the TLLI from the given BSSGP message.
153 * \param[in] bssgp pointer to start of BSSGP header
154 * \param[in] bssgp_len length of BSSGP message in octets
155 * \param[out] tlli TLLI (if any) in host byte order
156 * \returns 1 if TLLI found; 0 if none found; negative on parse error */
157int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli)
158{
159 const struct bssgp_normal_hdr *bgph;
160 uint8_t pdu_type;
161
162 if (bssgp_len < sizeof(struct bssgp_normal_hdr))
163 return -EINVAL;
164
165 bgph = (struct bssgp_normal_hdr *)bssgp;
166 pdu_type = bgph->pdu_type;
167
168 if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
169 pdu_type == BSSGP_PDUT_DL_UNITDATA) {
170 const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *)bssgp;
171 if (bssgp_len < sizeof(struct bssgp_ud_hdr))
172 return -EINVAL;
173 *tlli = osmo_load32be((const uint8_t *)&budh->tlli);
174 return 1;
175 } else {
176 const uint8_t *data = bgph->data;
177 size_t data_len = bssgp_len - sizeof(*bgph);
178 struct tlv_parsed tp;
179
180 if (bssgp_tlv_parse(&tp, data, data_len) < 0)
181 return -EINVAL;
182
183 if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
184 *tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
185 return 1;
186 }
187 }
188
189 /* No TLLI present in message */
190 return 0;
191}
192
Daniel Willmann76205712020-11-30 17:08:58 +0100193/* feed a message down the NSE */
194static int gbprox_relay2nse(struct msgb *old_msg, struct gbproxy_nse *nse,
Daniel Willmann35f7d332020-11-03 21:11:45 +0100195 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200196{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100197 OSMO_ASSERT(nse);
198 OSMO_ASSERT(nse->cfg);
199
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200200 /* create a copy of the message so the old one can
201 * be free()d safely when we return from gbprox_rcvmsg() */
Daniel Willmanne50550e2020-11-26 18:19:21 +0100202 struct gprs_ns2_inst *nsi = nse->cfg->nsi;
Daniel Willmann76205712020-11-30 17:08:58 +0100203 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2nse");
Daniel Willmann44fa2012021-02-12 04:55:40 +0100204 uint32_t tlli = 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200205 int rc;
206
Daniel Willmann98b1b452020-12-21 10:40:27 +0100207 DEBUGP(DGPRS, "NSE(%05u/%s)-BVC(%05u/??) proxying to NSE(%05u/%s)\n", msgb_nsei(msg),
208 !nse->sgsn_facing ? "SGSN" : "BSS", ns_bvci, nse->nsei, nse->sgsn_facing ? "SGSN" : "BSS");
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200209
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200210 /* Strip the old NS header, it will be replaced with a new one */
211 strip_ns_hdr(msg);
212
Harald Weltefe059582020-11-18 12:01:46 +0100213 /* TS 48.018 Section 5.4.2: The link selector parameter is
214 * defined in 3GPP TS 48.016. At one side of the Gb interface,
215 * all BSSGP UNITDATA PDUs related to an MS shall be passed with
216 * the same LSP, e.g. the LSP contains the MS's TLLI, to the
217 * underlying network service. */
Daniel Willmann44fa2012021-02-12 04:55:40 +0100218 gprs_gb_parse_tlli(msgb_data(msg), msgb_length(msg), &tlli);
Harald Weltefe059582020-11-18 12:01:46 +0100219
Daniel Willmann44fa2012021-02-12 04:55:40 +0100220 rc = bssgp2_nsi_tx_ptp(nsi, nse->nsei, ns_bvci, msg, tlli);
Daniel Willmann76205712020-11-30 17:08:58 +0100221 /* FIXME: We need a counter group for gbproxy_nse */
222 //if (rc < 0)
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200223 // rate_ctr_inc(rate_ctr_group_get_ctr(bvc->ctrg, GBPROX_PEER_CTR_TX_ERR));
Daniel Willmann76205712020-11-30 17:08:58 +0100224
225 return rc;
226}
227
Harald Welte560bdb32020-12-04 22:24:47 +0100228/* feed a message down the NS-VC associated with the specified bvc */
229static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,
Daniel Willmann76205712020-11-30 17:08:58 +0100230 uint16_t ns_bvci)
231{
232 int rc;
Harald Welte560bdb32020-12-04 22:24:47 +0100233 struct gbproxy_nse *nse = bvc->nse;
Daniel Willmann76205712020-11-30 17:08:58 +0100234 OSMO_ASSERT(nse);
235
236 rc = gbprox_relay2nse(old_msg, nse, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200237 if (rc < 0)
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200238 rate_ctr_inc(rate_ctr_group_get_ctr(bvc->ctrg, GBPROX_PEER_CTR_TX_ERR));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200239
240 return rc;
241}
242
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200243int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
244{
245 return 0;
246}
247
Harald Weltee5209642020-12-05 19:59:45 +0100248
249/***********************************************************************
250 * PTP BVC handling
251 ***********************************************************************/
252
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100253/* FIXME: Handle the tlli NULL case correctly,
254 * This function should take a generic selector
255 * and choose an sgsn based on that
256 */
257static struct gbproxy_sgsn *gbproxy_select_sgsn(struct gbproxy_config *cfg, const uint32_t *tlli)
258{
259 struct gbproxy_sgsn *sgsn = NULL;
260 struct gbproxy_sgsn *sgsn_avoid = NULL;
261
262 int tlli_type;
263 int16_t nri;
264 bool null_nri = false;
265
266 if (!tlli) {
Daniel Willmann37518b32021-05-27 18:13:36 +0200267 sgsn = gbproxy_sgsn_by_available(cfg);
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100268 if (!sgsn) {
Daniel Willmann37518b32021-05-27 18:13:36 +0200269 LOGP(DGPRS, LOGL_ERROR, "Could not find any available SGSN\n");
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100270 return NULL;
271 }
Daniel Willmann37518b32021-05-27 18:13:36 +0200272 LOGPSGSN(sgsn, LOGL_INFO, "Could not get TLLI, using first available SGSN\n");
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100273 return sgsn;
274 }
275
276 if (cfg->pool.nri_bitlen == 0) {
277 /* Pooling is disabled */
Daniel Willmann37518b32021-05-27 18:13:36 +0200278 sgsn = gbproxy_sgsn_by_available(cfg);
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100279 if (!sgsn) {
Daniel Willmann37518b32021-05-27 18:13:36 +0200280 LOGP(DGPRS, LOGL_ERROR, "Could not find any available SGSN\n");
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100281 return NULL;
282 }
283
Daniel Willmann37518b32021-05-27 18:13:36 +0200284 LOGPSGSN(sgsn, LOGL_INFO, "Pooling disabled, using first available SGSN\n");
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100285 } else {
286 /* Pooling is enabled, try to use the NRI for routing to an SGSN
287 * See 3GPP TS 23.236 Ch. 5.3.2 */
288 tlli_type = gprs_tlli_type(*tlli);
289 if (tlli_type == TLLI_LOCAL || tlli_type == TLLI_FOREIGN) {
290 /* Only get/use the NRI if tlli type is local */
291 osmo_tmsi_nri_v_get(&nri, *tlli, cfg->pool.nri_bitlen);
292 if (nri >= 0) {
293 /* Get the SGSN for the NRI */
294 sgsn = gbproxy_sgsn_by_nri(cfg, nri, &null_nri);
295 if (sgsn && !null_nri)
296 return sgsn;
297 /* If the NRI is the null NRI, we need to avoid the chosen SGSN */
298 if (null_nri && sgsn) {
299 sgsn_avoid = sgsn;
300 }
301 } else {
302 /* We couldn't get the NRI from the TLLI */
Daniel Willmanncd21afe2021-01-21 18:44:51 +0100303 LOGP(DGPRS, LOGL_ERROR, "Could not extract NRI from local TLLI %08x\n", *tlli);
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100304 }
Daniel Willmanncd21afe2021-01-21 18:44:51 +0100305 } else {
306 LOGP(DGPRS, LOGL_INFO, "TLLI %08x is neither local nor foreign, not routing by NRI\n", *tlli);
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100307 }
308 }
309
310 /* If we haven't found an SGSN yet we need to choose one, but avoid the one in sgsn_avoid
311 * NOTE: This function is not stable if the number of SGSNs or allow_attach changes
312 * We could implement TLLI tracking here, but 3GPP TS 23.236 Ch. 5.3.2 (see NOTE) argues that
313 * we can just wait for the MS to reattempt the procedure.
314 */
315 if (!sgsn)
316 sgsn = gbproxy_sgsn_by_tlli(cfg, sgsn_avoid, *tlli);
317
318 if (!sgsn) {
319 LOGP(DGPRS, LOGL_ERROR, "No suitable SGSN found for TLLI %u\n", *tlli);
320 return NULL;
321 }
322
323 return sgsn;
324}
325
326/*! Find the correct gbproxy_bvc given a cell and an SGSN
327 * \param[in] cfg The gbproxy configuration
328 * \param[in] cell The cell the message belongs to
329 * \param[in] tlli An optional TLLI used for tracking
330 * \return Returns 0 on success, otherwise a negative value
331 */
332static struct gbproxy_bvc *gbproxy_select_sgsn_bvc(struct gbproxy_config *cfg, struct gbproxy_cell *cell, const uint32_t *tlli)
333{
334 struct gbproxy_sgsn *sgsn;
335 struct gbproxy_bvc *sgsn_bvc = NULL;
Harald Welte02d7c482020-12-30 12:13:36 +0100336 int i;
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100337
338 sgsn = gbproxy_select_sgsn(cfg, tlli);
339 if (!sgsn) {
340 LOGPCELL(cell, LOGL_ERROR, "Could not find any SGSN, dropping message!\n");
341 return NULL;
342 }
343
344 /* Get the BVC for this SGSN/NSE */
Harald Welte02d7c482020-12-30 12:13:36 +0100345 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100346 sgsn_bvc = cell->sgsn_bvc[i];
347 if (!sgsn_bvc)
348 continue;
349 if (sgsn->nse != sgsn_bvc->nse)
350 continue;
351
352 return sgsn_bvc;
353 }
354
355 /* This shouldn't happen */
Daniel Willmanna648f3c2020-12-28 18:07:27 +0100356 LOGPCELL(cell, LOGL_ERROR, "Could not find matching BVC for SGSN %s, dropping message!\n", sgsn->name);
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100357 return NULL;
358}
359
360/*! Send a message to the next SGSN, possibly ignoring the null SGSN
361 * route an uplink message on a PTP-BVC to a SGSN using the TLLI
362 * \param[in] cell The cell the message belongs to
363 * \param[in] msg The BSSGP message
364 * \param[in] null_sgsn If not NULL then avoid this SGSN (because this message contains its null NRI)
365 * \param[in] tlli An optional TLLI used for tracking
366 * \return Returns 0 on success, otherwise a negative value
367 */
368static int gbprox_bss2sgsn_tlli(struct gbproxy_cell *cell, struct msgb *msg, const uint32_t *tlli,
Harald Weltee5209642020-12-05 19:59:45 +0100369 bool sig_bvci)
370{
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100371 struct gbproxy_config *cfg = cell->cfg;
Harald Weltee5209642020-12-05 19:59:45 +0100372 struct gbproxy_bvc *sgsn_bvc;
Harald Weltee5209642020-12-05 19:59:45 +0100373
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100374 sgsn_bvc = gbproxy_select_sgsn_bvc(cfg, cell, tlli);
375 if (!sgsn_bvc) {
376 LOGPCELL(cell, LOGL_NOTICE, "Could not find any SGSN for TLLI %u, dropping message!\n", *tlli);
377 return -EINVAL;
Harald Weltee5209642020-12-05 19:59:45 +0100378 }
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100379
380 return gbprox_relay2peer(msg, sgsn_bvc, sig_bvci ? 0 : sgsn_bvc->bvci);
Harald Weltee5209642020-12-05 19:59:45 +0100381}
382
Daniel Willmann22311802021-11-02 11:54:27 +0100383static int gbproxy_decode_bssgp(const struct bssgp_normal_hdr *bgph, int msg_len, struct tlv_parsed *tp, const char *log_pfx)
384{
385 int rc;
386
387 /* UNITDATA PDUs have a different header than the other PDUs */
388 if (bgph->pdu_type == BSSGP_PDUT_UL_UNITDATA || bgph->pdu_type == BSSGP_PDUT_DL_UNITDATA) {
389 const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) bgph;
390 if (msg_len < sizeof(*budh))
Daniel Willmannf689a8a2021-11-18 15:27:37 +0100391 return OSMO_TLVP_ERR_MAND_IE_MISSING;
Daniel Willmann22311802021-11-02 11:54:27 +0100392 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp, 1, budh->pdu_type, budh->data,
393 msg_len - sizeof(*budh), 0, 0, DGPRS, log_pfx);
394 /* populate TLLI from the fixed headser into the TLV-parsed array so later code
395 * doesn't have to worry where the TLLI came from */
396 tp->lv[BSSGP_IE_TLLI].len = 4;
397 tp->lv[BSSGP_IE_TLLI].val = (const uint8_t *) &budh->tlli;
398 } else {
399 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp, 1, bgph->pdu_type, bgph->data,
400 msg_len - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
401 }
402
403 return rc;
404}
405
Daniel Willmann5a148372021-10-29 18:28:13 +0200406static int gbproxy_tlli_from_status_pdu(struct tlv_parsed *tp, uint32_t *tlli, char *log_pfx);
407
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200408/* Receive an incoming PTP message from a BSS-side NS-VC */
Harald Weltee5209642020-12-05 19:59:45 +0100409static int gbprox_rx_ptp_from_bss(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200410{
Harald Welte278dd272020-12-06 13:35:24 +0100411 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Weltee5209642020-12-05 19:59:45 +0100412 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
413 struct gbproxy_bvc *bss_bvc;
414 struct tlv_parsed tp;
415 char log_pfx[32];
416 uint32_t tlli;
417 int rc;
418
419 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);
420
421 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200422
Daniel Willmann06331ac2020-12-10 17:59:46 +0100423 if (ns_bvci == 0 || ns_bvci == 1) {
Harald Weltee5209642020-12-05 19:59:45 +0100424 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not PTP\n", log_pfx, ns_bvci);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100425 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100426 }
427
428 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
Harald Weltee5209642020-12-05 19:59:45 +0100429 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100430 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100431 }
432
433 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_UL)) {
Harald Weltee5209642020-12-05 19:59:45 +0100434 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100435 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100436 }
437
Harald Weltee5209642020-12-05 19:59:45 +0100438 bss_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);
439 if (!bss_bvc) {
440 LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for PTP message, discarding\n",
441 log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100442 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200443 }
444
Daniel Willmann22311802021-11-02 11:54:27 +0100445 rc = gbproxy_decode_bssgp(bgph, msgb_bssgp_len(msg), &tp, log_pfx);
Harald Weltee5209642020-12-05 19:59:45 +0100446 if (rc < 0) {
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200447 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_BSS));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100448 return tx_status_from_tlvp(nse, rc, msg);
Harald Weltee5209642020-12-05 19:59:45 +0100449 }
Harald Welte85a40272020-12-08 21:43:22 +0100450 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
451 msgb_bcid(msg) = (void *)&tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200452
Harald Weltee5209642020-12-05 19:59:45 +0100453 switch (bgph->pdu_type) {
454 case BSSGP_PDUT_UL_UNITDATA:
455 case BSSGP_PDUT_RA_CAPA_UPDATE:
456 case BSSGP_PDUT_FLOW_CONTROL_MS:
457 case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
458 case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
459 case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
460 case BSSGP_PDUT_MODIFY_BSS_PFC_ACK:
461 case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
462 case BSSGP_PDUT_FLOW_CONTROL_PFC:
463 case BSSGP_PDUT_DELETE_BSS_PFC_REQ:
464 case BSSGP_PDUT_PS_HO_REQUIRED:
465 case BSSGP_PDUT_PS_HO_REQUEST_ACK:
466 case BSSGP_PDUT_PS_HO_REQUEST_NACK:
467 case BSSGP_PDUT_PS_HO_COMPLETE:
468 case BSSGP_PDUT_PS_HO_CANCEL:
469 /* We can route based on TLLI-NRI */
470 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100471 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, &tlli, false);
Harald Weltee5209642020-12-05 19:59:45 +0100472 break;
473 case BSSGP_PDUT_RADIO_STATUS:
474 if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
475 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100476 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, &tlli, false);
Harald Weltee5209642020-12-05 19:59:45 +0100477 } else if (TLVP_PRESENT(&tp, BSSGP_IE_TMSI)) {
478 /* we treat the TMSI like a TLLI and extract the NRI from it */
479 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TMSI));
Daniel Willmann8b3ed292021-01-21 18:46:51 +0100480 /* Convert the TMSI into a FOREIGN TLLI so it is routed appropriately */
481 tlli = gprs_tmsi2tlli(tlli, TLLI_FOREIGN);
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100482 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, &tlli, false);
Harald Weltee5209642020-12-05 19:59:45 +0100483 } else if (TLVP_PRESENT(&tp, BSSGP_IE_IMSI)) {
Daniel Willmann5193f222021-01-11 05:00:46 +0100484 /* FIXME: Use the IMSI as selector? */
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100485 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, NULL, false);
Harald Weltee5209642020-12-05 19:59:45 +0100486 } else
487 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx RADIO-STATUS without any of the conditional IEs\n");
488 break;
489 case BSSGP_PDUT_DUMMY_PAGING_PS_RESP:
490 case BSSGP_PDUT_PAGING_PS_REJECT:
Daniel Willmann5614e572021-01-18 18:38:27 +0100491 {
492 /* Route according to IMSI<->NSE cache entry */
493 struct osmo_mobile_identity mi;
494 const uint8_t *mi_data = TLVP_VAL(&tp, BSSGP_IE_IMSI);
495 uint8_t mi_len = TLVP_LEN(&tp, BSSGP_IE_IMSI);
496 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +0200497 nse = gbproxy_nse_by_imsi(nse->cfg, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann5614e572021-01-18 18:38:27 +0100498 if (nse) {
499 OSMO_ASSERT(nse->sgsn_facing);
500 rc = gbprox_relay2nse(msg, nse, ns_bvci);
501 } else {
Daniel Willmann82669182021-01-19 11:37:55 +0100502 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx unmatched %s with IMSI %s\n", pdut_name, mi.imsi);
Daniel Willmann5614e572021-01-18 18:38:27 +0100503 }
Harald Weltee5209642020-12-05 19:59:45 +0100504 break;
Daniel Willmann5614e572021-01-18 18:38:27 +0100505 }
Harald Weltee5209642020-12-05 19:59:45 +0100506 case BSSGP_PDUT_FLOW_CONTROL_BVC:
Harald Welte85a40272020-12-08 21:43:22 +0100507 osmo_fsm_inst_dispatch(bss_bvc->fi, BSSGP_BVCFSM_E_RX_FC_BVC, msg);
Harald Weltee5209642020-12-05 19:59:45 +0100508 break;
509 case BSSGP_PDUT_STATUS:
Daniel Willmann5a148372021-10-29 18:28:13 +0200510 {
511 struct gbproxy_sgsn *sgsn;
512 /* Check if the status needs to be terminated locally */
513 uint8_t cause = *TLVP_VAL(&tp, BSSGP_IE_CAUSE);
514
515 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s)\n", cause,
516 bssgp_cause_str(cause));
517
518 if (gbproxy_tlli_from_status_pdu(&tp, &tlli, log_pfx) == 0)
519 sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
520 else
521 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
522
523 if (!sgsn) {
524 rc = -EINVAL;
Harald Weltee5209642020-12-05 19:59:45 +0100525 break;
Daniel Willmann5a148372021-10-29 18:28:13 +0200526 }
527
528 rc = gbprox_relay2nse(msg, sgsn->nse, ns_bvci);
Harald Weltee5209642020-12-05 19:59:45 +0100529 break;
530 }
Daniel Willmann5a148372021-10-29 18:28:13 +0200531 }
Harald Weltee5209642020-12-05 19:59:45 +0100532
533 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200534}
535
536/* Receive an incoming PTP message from a SGSN-side NS-VC */
Harald Weltee5209642020-12-05 19:59:45 +0100537static int gbprox_rx_ptp_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200538{
Harald Welte278dd272020-12-06 13:35:24 +0100539 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Weltee5209642020-12-05 19:59:45 +0100540 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
541 struct gbproxy_bvc *sgsn_bvc, *bss_bvc;
Harald Welte85a40272020-12-08 21:43:22 +0100542 struct tlv_parsed tp;
Harald Weltee5209642020-12-05 19:59:45 +0100543 char log_pfx[32];
Harald Welte85a40272020-12-08 21:43:22 +0100544 int rc;
Harald Weltee5209642020-12-05 19:59:45 +0100545
546 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);
547
548 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200549
Daniel Willmann06331ac2020-12-10 17:59:46 +0100550 if (ns_bvci == 0 || ns_bvci == 1) {
Harald Weltee5209642020-12-05 19:59:45 +0100551 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI is not PTP\n", log_pfx);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100552 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100553 }
554
555 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
Harald Weltee5209642020-12-05 19:59:45 +0100556 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100557 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100558 }
559
560 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_DL)) {
Harald Weltee5209642020-12-05 19:59:45 +0100561 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100562 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100563 }
564
Harald Weltee5209642020-12-05 19:59:45 +0100565 sgsn_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);
566 if (!sgsn_bvc) {
567 LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for for PTP message, discarding\n",
568 log_pfx, pdut_name);
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200569 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100570 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200571 }
572
Harald Weltee5209642020-12-05 19:59:45 +0100573 if (!bssgp_bvc_fsm_is_unblocked(sgsn_bvc->fi)) {
574 LOGPBVC(sgsn_bvc, LOGL_NOTICE, "Rx %s: Dropping on blocked BVC\n", pdut_name);
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200575 rate_ctr_inc(rate_ctr_group_get_ctr(sgsn_bvc->ctrg, GBPROX_PEER_CTR_DROPPED));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100576 return tx_status(nse, ns_bvci, BSSGP_CAUSE_BVCI_BLOCKED, &ns_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200577 }
Harald Welte85a40272020-12-08 21:43:22 +0100578
Daniel Willmann22311802021-11-02 11:54:27 +0100579 rc = gbproxy_decode_bssgp(bgph, msgb_bssgp_len(msg), &tp, log_pfx);
Harald Welte85a40272020-12-08 21:43:22 +0100580 if (rc < 0) {
Daniel Willmanncfb6f172021-11-02 11:55:06 +0100581 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_SGSN));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100582 return tx_status_from_tlvp(nse, rc, msg);
Harald Welte85a40272020-12-08 21:43:22 +0100583 }
584 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
585 msgb_bcid(msg) = (void *)&tp;
586
Harald Weltee5209642020-12-05 19:59:45 +0100587 OSMO_ASSERT(sgsn_bvc->cell);
588 bss_bvc = sgsn_bvc->cell->bss_bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200589
Harald Welte85a40272020-12-08 21:43:22 +0100590 switch (bgph->pdu_type) {
591 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
592 return osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_FC_BVC_ACK, msg);
Daniel Willmann5614e572021-01-18 18:38:27 +0100593 case BSSGP_PDUT_DUMMY_PAGING_PS:
594 case BSSGP_PDUT_PAGING_PS:
595 {
596 /* Cache the IMSI<->NSE to route PAGING REJECT */
597 struct osmo_mobile_identity mi;
598 const uint8_t *mi_data = TLVP_VAL(&tp, BSSGP_IE_IMSI);
599 uint8_t mi_len = TLVP_LEN(&tp, BSSGP_IE_IMSI);
600 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +0200601 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann5614e572021-01-18 18:38:27 +0100602 break;
Harald Welte85a40272020-12-08 21:43:22 +0100603 }
Daniel Willmann5614e572021-01-18 18:38:27 +0100604 default:
605 break;
606 }
607 return gbprox_relay2peer(msg, bss_bvc, bss_bvc->bvci);
Harald Welte85a40272020-12-08 21:43:22 +0100608
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200609}
610
Harald Weltee5209642020-12-05 19:59:45 +0100611/***********************************************************************
612 * BVC FSM call-backs
613 ***********************************************************************/
Harald Welte7df1e5a2020-12-02 22:53:26 +0100614
Harald Weltee5209642020-12-05 19:59:45 +0100615/* helper function to dispatch a FSM event to all SGSN-side BVC FSMs of a cell */
616static void dispatch_to_all_sgsn_bvc(struct gbproxy_cell *cell, uint32_t event, void *priv)
617{
618 unsigned int i;
619
620 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
621 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[i];
622 if (!sgsn_bvc)
623 continue;
624 osmo_fsm_inst_dispatch(sgsn_bvc->fi, event, priv);
625 }
626}
627
628/* BVC FSM informs us about a BSS-side reset of the signaling BVC */
629static void bss_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
630 uint16_t cell_id, uint8_t cause, void *priv)
631{
632 struct gbproxy_bvc *sig_bvc = priv;
633 struct gbproxy_nse *nse = sig_bvc->nse;
634 struct gbproxy_bvc *ptp_bvc;
635 unsigned int i;
636
637 /* BLOCK all SGSN-side PTP BVC within this NSE */
638 hash_for_each(nse->bvcs, i, ptp_bvc, list) {
639 if (ptp_bvc == sig_bvc)
640 continue;
641 OSMO_ASSERT(ptp_bvc->cell);
642
643 dispatch_to_all_sgsn_bvc(ptp_bvc->cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
Harald Weltef9e149b2020-12-02 23:29:38 +0100644 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100645
Harald Weltee5209642020-12-05 19:59:45 +0100646 /* Delete all BSS-side PTP BVC within this NSE */
647 gbproxy_cleanup_bvcs(nse, 0);
648
649 /* TODO: we keep the "CELL" around for now, re-connecting it to
650 * any (later) new PTP-BVC for that BVCI. Not sure if that's the
651 * best idea ? */
652}
653
654/* forward declaration */
655static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops;
656
657static const struct bssgp_bvc_fsm_ops bss_sig_bvc_fsm_ops = {
658 .reset_notification = bss_sig_bvc_reset_notif,
659};
660
661/* BVC FSM informs us about a BSS-side reset of a PTP BVC */
662static void bss_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
663 uint16_t cell_id, uint8_t cause, void *priv)
664{
665 struct gbproxy_bvc *bvc = priv;
666 struct gbproxy_config *cfg = bvc->nse->cfg;
Harald Welte664c24e2020-12-12 15:01:17 +0100667 struct gbproxy_nse *sgsn_nse;
Harald Weltee5209642020-12-05 19:59:45 +0100668 unsigned int i;
669
670 OSMO_ASSERT(bvci != 0);
671
672 if (!bvc->cell) {
673 /* see if we have a CELL dangling around */
674 bvc->cell = gbproxy_cell_by_bvci(cfg, bvci);
675 if (bvc->cell) {
676 /* the CELL already exists. This means either it * was created before at an
677 * earlier PTP BVC-RESET, or that there are non-unique BVCIs and hence a
678 * malconfiguration */
679 if (bvc->cell->bss_bvc) {
680 LOGPBVC(bvc, LOGL_NOTICE, "Rx BVC-RESET via this NSE, but CELL already "
681 "has BVC on NSEI=%05u\n", bvc->cell->bss_bvc->nse->nsei);
682 LOGPBVC(bvc->cell->bss_bvc, LOGL_NOTICE, "Destroying due to conflicting "
683 "BVCI configuration (new NSEI=%05u)!\n", bvc->nse->nsei);
684 gbproxy_bvc_free(bvc->cell->bss_bvc);
Daniel Willmann28ec0e32021-12-06 16:47:22 +0100685 bvc->cell = NULL;
686 } else {
687 LOGPBVC(bvc, LOGL_ERROR, "Found cell without BSS BVC, this should not happen!");
Harald Weltee5209642020-12-05 19:59:45 +0100688 }
Harald Weltee5209642020-12-05 19:59:45 +0100689 }
690 }
691
692 if (!bvc->cell) {
Harald Weltee5209642020-12-05 19:59:45 +0100693 /* if we end up here, it means this is the first time we received a BVC-RESET
694 * for this BVC. We need to create the 'cell' data structure and the SGSN-side
695 * BVC counterparts */
696
Philipp Maiere4597ec2021-02-09 16:02:00 +0100697 bvc->cell = gbproxy_cell_alloc(cfg, bvci, ra_id, cell_id);
Harald Weltee5209642020-12-05 19:59:45 +0100698 OSMO_ASSERT(bvc->cell);
699
700 /* link us to the cell and vice-versa */
701 bvc->cell->bss_bvc = bvc;
Harald Welte664c24e2020-12-12 15:01:17 +0100702 }
Harald Weltee5209642020-12-05 19:59:45 +0100703
Daniel Willmann6701d272021-04-08 08:39:12 +0200704 /* Ensure we have the correct RA/CELL ID */
705 if (!gsm48_ra_equal(&bvc->cell->id.raid, ra_id)) {
706 LOGPBVC(bvc, LOGL_NOTICE, "RAID changed from %s to %s, updating cell\n", osmo_rai_name(&bvc->cell->id.raid), osmo_rai_name(ra_id));
707 memcpy(&bvc->cell->id.raid, ra_id, sizeof(*ra_id));
708 }
709 if (bvc->cell->id.cid != cell_id) {
710 LOGPBVC(bvc, LOGL_NOTICE, "CellID changed from %05d to %05d, updating cell\n", bvc->cell->id.cid, cell_id);
711 bvc->cell->id.cid = cell_id;
712 }
713
714 /* Reallocate SGSN-side BVCs of the cell, and reset them
Daniel Willmannf9902c52021-11-12 15:52:03 +0100715 * Removing and reallocating is needed because the ra_id/cell_id might have changed */
Harald Welte664c24e2020-12-12 15:01:17 +0100716 hash_for_each(cfg->sgsn_nses, i, sgsn_nse, list) {
717 struct gbproxy_bvc *sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
Daniel Willmanndc763fd2021-09-24 16:45:38 +0200718 if (!sgsn_bvc)
719 sgsn_bvc = gbproxy_bvc_by_bvci_inactive(sgsn_nse, bvci);
Harald Welte664c24e2020-12-12 15:01:17 +0100720 if (sgsn_bvc)
Daniel Willmann6701d272021-04-08 08:39:12 +0200721 gbproxy_bvc_free(sgsn_bvc);
Harald Weltee5209642020-12-05 19:59:45 +0100722
Daniel Willmann6701d272021-04-08 08:39:12 +0200723 sgsn_bvc = gbproxy_bvc_alloc(sgsn_nse, bvci);
724 OSMO_ASSERT(sgsn_bvc);
725 sgsn_bvc->cell = bvc->cell;
Daniel Willmann6701d272021-04-08 08:39:12 +0200726 sgsn_bvc->fi = bssgp_bvc_fsm_alloc_ptp_bss(sgsn_bvc, cfg->nsi, sgsn_nse->nsei,
727 bvci, ra_id, cell_id);
728 OSMO_ASSERT(sgsn_bvc->fi);
729 bssgp_bvc_fsm_set_max_pdu_len(sgsn_bvc->fi, sgsn_nse->max_sdu_len);
730 bssgp_bvc_fsm_set_ops(sgsn_bvc->fi, &sgsn_ptp_bvc_fsm_ops, sgsn_bvc);
731 gbproxy_cell_add_sgsn_bvc(bvc->cell, sgsn_bvc);
Harald Weltee5209642020-12-05 19:59:45 +0100732 }
733
734 /* Trigger outbound BVC-RESET procedure toward each SGSN */
735 dispatch_to_all_sgsn_bvc(bvc->cell, BSSGP_BVCFSM_E_REQ_RESET, &cause);
736}
737
738/* BVC FSM informs us about a BSS-side FSM state change */
739static void bss_ptp_bvc_state_chg_notif(uint16_t nsei, uint16_t bvci, int old_state, int state, void *priv)
740{
741 struct gbproxy_bvc *bvc = priv;
742 struct gbproxy_cell *cell = bvc->cell;
743 uint8_t cause = bssgp_bvc_fsm_get_block_cause(bvc->fi);
744
745 /* we have just been created but due to callback ordering the cell is not associated */
746 if (!cell)
747 return;
748
749 switch (state) {
750 case BSSGP_BVCFSM_S_BLOCKED:
751 /* block the corresponding SGSN-side PTP BVCs */
752 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
753 break;
754 case BSSGP_BVCFSM_S_UNBLOCKED:
755 /* unblock the corresponding SGSN-side PTP BVCs */
756 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_UNBLOCK, NULL);
757 break;
758 }
759}
760
Harald Welte85a40272020-12-08 21:43:22 +0100761/* BVC FSM informs us about BVC-FC PDU receive */
762static void bss_ptp_bvc_fc_bvc(uint16_t nsei, uint16_t bvci, const struct bssgp2_flow_ctrl *fc, void *priv)
763{
Harald Welte209dc9f2020-12-12 19:02:16 +0100764 struct bssgp2_flow_ctrl fc_reduced;
Harald Welte85a40272020-12-08 21:43:22 +0100765 struct gbproxy_bvc *bss_bvc = priv;
Harald Welte209dc9f2020-12-12 19:02:16 +0100766 struct gbproxy_cell *cell;
767 struct gbproxy_config *cfg;
Harald Welte85a40272020-12-08 21:43:22 +0100768
Harald Welte209dc9f2020-12-12 19:02:16 +0100769 OSMO_ASSERT(bss_bvc);
770 OSMO_ASSERT(fc);
771
772 cell = bss_bvc->cell;
Harald Welte85a40272020-12-08 21:43:22 +0100773 if (!cell)
774 return;
775
Harald Welte209dc9f2020-12-12 19:02:16 +0100776 cfg = cell->cfg;
Harald Welte85a40272020-12-08 21:43:22 +0100777
Harald Welte209dc9f2020-12-12 19:02:16 +0100778 /* reduce / scale according to configuration to make sure we only advertise a fraction
779 * of the capacity to each of the SGSNs in the pool */
780 fc_reduced = *fc;
781 fc_reduced.bucket_size_max = (fc->bucket_size_max * cfg->pool.bvc_fc_ratio) / 100;
782 fc_reduced.bucket_leak_rate = (fc->bucket_leak_rate * cfg->pool.bvc_fc_ratio) / 100;
783 /* we don't modify the per-MS related values as any single MS is only served by one SGSN */
784
785 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_FC_BVC, (void *) &fc_reduced);
Harald Welte85a40272020-12-08 21:43:22 +0100786}
787
Harald Weltee5209642020-12-05 19:59:45 +0100788static const struct bssgp_bvc_fsm_ops bss_ptp_bvc_fsm_ops = {
789 .reset_notification = bss_ptp_bvc_reset_notif,
790 .state_chg_notification = bss_ptp_bvc_state_chg_notif,
Harald Welte85a40272020-12-08 21:43:22 +0100791 .rx_fc_bvc = bss_ptp_bvc_fc_bvc,
Harald Weltee5209642020-12-05 19:59:45 +0100792};
793
794/* BVC FSM informs us about a SGSN-side reset of a PTP BVC */
795static void sgsn_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
796 uint16_t cell_id, uint8_t cause, void *priv)
797{
798 struct gbproxy_bvc *bvc = priv;
799
800 if (!bvc->cell) {
801 LOGPBVC(bvc, LOGL_ERROR, "RESET of PTP BVC on SGSN side for which we have no BSS?\n");
802 return;
803 }
804
805 OSMO_ASSERT(bvc->cell->bss_bvc);
806
807 /* request reset of BSS-facing PTP-BVC */
808 osmo_fsm_inst_dispatch(bvc->cell->bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
809}
810
811static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops = {
812 .reset_notification = sgsn_ptp_bvc_reset_notif,
813};
814
815/* BVC FSM informs us about a SGSN-side reset of the signaling BVC */
816static void sgsn_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
817 uint16_t cell_id, uint8_t cause, void *priv)
818{
819 struct gbproxy_bvc *bvc = priv;
820 struct gbproxy_config *cfg = bvc->nse->cfg;
821 struct gbproxy_nse *bss_nse;
822 unsigned int i;
823
824 /* delete all SGSN-side PTP BVC for this SGSN */
825 gbproxy_cleanup_bvcs(bvc->nse, 0);
826 /* FIXME: what to do about the cells? */
827 /* FIXME: do we really want to RESET all signaling BVC on the BSS and affect all other SGSN? */
828
829 /* we need to trigger generating a reset procedure towards each BSS side signaling BVC */
830 hash_for_each(cfg->bss_nses, i, bss_nse, list) {
831 struct gbproxy_bvc *bss_bvc = gbproxy_bvc_by_bvci(bss_nse, 0);
832 if (!bss_bvc) {
833 LOGPNSE(bss_nse, LOGL_ERROR, "Doesn't have BVC with BVCI=0 ?!?\n");
834 continue;
835 }
836 osmo_fsm_inst_dispatch(bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
837 }
838}
839
840const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops = {
841 .reset_notification = sgsn_sig_bvc_reset_notif,
842};
843
844/***********************************************************************
845 * Signaling BVC handling
846 ***********************************************************************/
847
848/* process a BVC-RESET message from the BSS side */
849static int rx_bvc_reset_from_bss(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp)
850{
851 struct gbproxy_bvc *from_bvc = NULL;
852 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
853 uint32_t features = 0; // FIXME: make configurable
854
855 LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", bvci);
856
Harald Welte314647b2020-12-02 23:03:22 +0100857 if (bvci == 0) {
858 /* If we receive a BVC reset on the signalling endpoint, we
859 * don't want the SGSN to reset, as the signalling endpoint
860 * is common for all point-to-point BVCs (and thus all BTS) */
Harald Welte324f0652020-12-02 23:06:37 +0100861
Harald Weltee5209642020-12-05 19:59:45 +0100862 from_bvc = gbproxy_bvc_by_bvci(nse, 0);
Harald Welte560bdb32020-12-04 22:24:47 +0100863 if (!from_bvc) {
Harald Weltee5209642020-12-05 19:59:45 +0100864 from_bvc = gbproxy_bvc_alloc(nse, 0);
865 OSMO_ASSERT(from_bvc);
866 from_bvc->fi = bssgp_bvc_fsm_alloc_sig_sgsn(from_bvc, nse->cfg->nsi, nse->nsei, features);
867 if (!from_bvc->fi) {
868 LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");
869 gbproxy_bvc_free(from_bvc);
870 return -ENOMEM;
Harald Welte7df1e5a2020-12-02 22:53:26 +0100871 }
Daniel Willmanna8b61652021-02-12 05:05:14 +0100872 bssgp_bvc_fsm_set_max_pdu_len(from_bvc->fi, nse->max_sdu_len);
Harald Weltee5209642020-12-05 19:59:45 +0100873 bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_sig_bvc_fsm_ops, from_bvc);
874 }
875 } else {
876 from_bvc = gbproxy_bvc_by_bvci(nse, bvci);
877 if (!from_bvc) {
Harald Welte7df1e5a2020-12-02 22:53:26 +0100878 /* if a PTP-BVC is reset, and we don't know that
Harald Welte560bdb32020-12-04 22:24:47 +0100879 * PTP-BVCI yet, we should allocate a new bvc */
880 from_bvc = gbproxy_bvc_alloc(nse, bvci);
881 OSMO_ASSERT(from_bvc);
Harald Weltee5209642020-12-05 19:59:45 +0100882 from_bvc->fi = bssgp_bvc_fsm_alloc_ptp_sgsn(from_bvc, nse->cfg->nsi,
883 nse->nsei, bvci);
884 if (!from_bvc->fi) {
885 LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");
886 gbproxy_bvc_free(from_bvc);
887 return -ENOMEM;
888 }
Daniel Willmanna8b61652021-02-12 05:05:14 +0100889 bssgp_bvc_fsm_set_max_pdu_len(from_bvc->fi, nse->max_sdu_len);
Harald Weltee5209642020-12-05 19:59:45 +0100890 bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_ptp_bvc_fsm_ops, from_bvc);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100891 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100892 }
Harald Weltee5209642020-12-05 19:59:45 +0100893 /* hand into FSM for further processing */
894 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
895 return 0;
Harald Welte7df1e5a2020-12-02 22:53:26 +0100896}
897
Philipp Maier1c5766b2021-02-09 17:03:03 +0100898/* Receive an incoming RIM message from a BSS-side NS-VC */
899static int gbprox_rx_rim_from_bss(struct tlv_parsed *tp, struct gbproxy_nse *nse, struct msgb *msg, char *log_pfx,
900 const char *pdut_name)
901{
902 struct gbproxy_sgsn *sgsn;
903 struct gbproxy_cell *dest_cell;
904 struct gbproxy_cell *src_cell;
905 struct bssgp_rim_routing_info dest_ri;
906 struct bssgp_rim_routing_info src_ri;
907 int rc;
Philipp Maier4499cf42021-02-10 17:54:44 +0100908 char ri_src_str[64];
909 char ri_dest_str[64];
Daniel Willmannf8cba652021-02-12 04:59:47 +0100910 uint16_t ns_bvci = msgb_bvci(msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100911
912 rc = bssgp_parse_rim_ri(&dest_ri, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
913 TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
914 if (rc < 0) {
915 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse destination RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100916 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100917 }
918 rc = bssgp_parse_rim_ri(&src_ri, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
919 TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
920 if (rc < 0) {
921 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse source RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100922 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100923 }
924
925 /* Since gbproxy is 2G only we do not expect to get RIM messages only from GERAN cells. */
926 if (src_ri.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
927 LOGP(DGPRS, LOGL_ERROR, "%s %s source RIM routing info is not GERAN (%s)\n", log_pfx, pdut_name,
928 bssgp_rim_ri_name(&src_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100929 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100930 }
931
932 /* Lookup source cell to make sure that the source RIM routing information actually belongs
933 * to a valid cell that we know */
934 src_cell = gbproxy_cell_by_cellid(nse->cfg, &src_ri.geran.raid, src_ri.geran.cid);
935 if (!src_cell) {
936 LOGP(DGPRS, LOGL_NOTICE, "%s %s cannot find cell for source RIM routing info (%s)\n", log_pfx,
937 pdut_name, bssgp_rim_ri_name(&src_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100938 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100939 }
940
941 /* TODO: Use bssgp_bvc_get_features_negotiated(src_cell->bss_bvc->fi) to check if the the BSS sided BVC actually
942 * did negotiate RIM support. If not we should respond with a BSSGP STATUS message. The cause code should be
943 * BSSGP_CAUSE_PDU_INCOMP_FEAT. */
944
945 /* If Destination is known by gbproxy, route directly */
946 if (dest_ri.discr == BSSGP_RIM_ROUTING_INFO_GERAN) {
947 dest_cell = gbproxy_cell_by_cellid(nse->cfg, &dest_ri.geran.raid, dest_ri.geran.cid);
948 if (dest_cell) {
949 /* TODO: Also check if dest_cell->bss_bvc is RIM-capable (see also above). If not we should
950 * respond with a BSSGP STATUS message as well because it also would make no sense to try
951 * routing the RIM message to the next RIM-capable SGSN. */
Philipp Maier4499cf42021-02-10 17:54:44 +0100952 LOGP(DLBSSGP, LOGL_DEBUG, "%s %s relaying to peer (nsei=%u) RIM-PDU: src=%s, dest=%s\n",
953 log_pfx, pdut_name, dest_cell->bss_bvc->nse->nsei,
954 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &src_ri),
955 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &dest_ri));
Philipp Maier1c5766b2021-02-09 17:03:03 +0100956 return gbprox_relay2peer(msg, dest_cell->bss_bvc, 0);
957 }
958 }
959
960 /* Otherwise pass on to a RIM-capable SGSN */
961 /* TODO: We need to extend gbproxy_select_sgsn() so that it selects a RIM-capable SGSN, at the moment we just
962 * get any SGSN and just assume that it is RIM-capable. */
963 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
964 if (!sgsn) {
965 LOGP(DGPRS, LOGL_NOTICE,
966 "%s %s cannot route RIM message (%s to %s) since no RIM capable SGSN is found!\n", log_pfx,
967 pdut_name, bssgp_rim_ri_name(&src_ri), bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100968 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100969 }
Philipp Maier4499cf42021-02-10 17:54:44 +0100970 LOGP(DLBSSGP, LOGL_DEBUG, "%s %s relaying to SGSN(%05u/%s) RIM-PDU: src=%s, dest=%s\n",
971 log_pfx, pdut_name, sgsn->nse->nsei, sgsn->name,
972 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &src_ri),
973 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &dest_ri));
Philipp Maier1c5766b2021-02-09 17:03:03 +0100974
975 return gbprox_relay2nse(msg, sgsn->nse, 0);
976}
977
Daniel Willmann6ec5f952021-10-28 16:13:03 +0200978/* Extract the TLLI from the PDU-in-error of the STATUS PDU (if available) */
979static int gbproxy_tlli_from_status_pdu(struct tlv_parsed *tp, uint32_t *tlli, char *log_pfx)
Daniel Willmann7d37cbb2021-09-29 11:51:51 +0200980{
981 int rc;
982 int pdu_len = TLVP_LEN(&tp[0], BSSGP_IE_PDU_IN_ERROR);
983 const uint8_t *pdu_data = TLVP_VAL(&tp[0], BSSGP_IE_PDU_IN_ERROR);
984 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)pdu_data;
Daniel Willmann01416282021-11-02 11:55:57 +0100985 struct tlv_parsed tp_inner;
Daniel Willmann7d37cbb2021-09-29 11:51:51 +0200986
Daniel Willmann01416282021-11-02 11:55:57 +0100987 rc = gbproxy_decode_bssgp(bgph, pdu_len, &tp_inner, log_pfx);
Daniel Willmannaf2e9b32021-11-18 15:27:49 +0100988 /* Ignore decode failure due to truncated message */
989 if (rc < 0 && rc != OSMO_TLVP_ERR_OFS_BEYOND_BUFFER)
Daniel Willmann7d37cbb2021-09-29 11:51:51 +0200990 return rc;
991
Daniel Willmann01416282021-11-02 11:55:57 +0100992 if (TLVP_PRESENT(&tp_inner, BSSGP_IE_TLLI)) {
993 *tlli = osmo_load32be(TLVP_VAL(&tp_inner, BSSGP_IE_TLLI));
994 } else if (TLVP_PRESENT(&tp_inner, BSSGP_IE_TMSI)) {
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +0200995 /* we treat the TMSI like a TLLI and extract the NRI from it */
Daniel Willmann01416282021-11-02 11:55:57 +0100996 *tlli = osmo_load32be(TLVP_VAL(&tp_inner, BSSGP_IE_TMSI));
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +0200997 /* Convert the TMSI into a FOREIGN TLLI so it is routed appropriately */
998 *tlli = gprs_tmsi2tlli(*tlli, TLLI_FOREIGN);
999 } else {
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001000 return -ENOENT;
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +02001001 }
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001002
1003 return 0;
1004}
1005
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001006/* Extract the BVCI from the PDU-in-error of the STATUS PDU (if available) */
1007static int gbproxy_bvci_from_status_pdu(struct tlv_parsed *tp, uint16_t *bvci, char *log_pfx)
1008{
1009 int rc;
1010 int pdu_len = TLVP_LEN(&tp[0], BSSGP_IE_PDU_IN_ERROR);
1011 const uint8_t *pdu_data = TLVP_VAL(&tp[0], BSSGP_IE_PDU_IN_ERROR);
1012 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)pdu_data;
Daniel Willmann01416282021-11-02 11:55:57 +01001013 struct tlv_parsed tp_inner;
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001014
Daniel Willmann01416282021-11-02 11:55:57 +01001015 rc = gbproxy_decode_bssgp(bgph, pdu_len, &tp_inner, log_pfx);
Daniel Willmannaf2e9b32021-11-18 15:27:49 +01001016 /* Ignore decode failure due to truncated message */
1017 if (rc < 0 && rc != OSMO_TLVP_ERR_OFS_BEYOND_BUFFER)
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001018 return rc;
1019
Daniel Willmann01416282021-11-02 11:55:57 +01001020 if (TLVP_PRESENT(&tp_inner, BSSGP_IE_BVCI))
1021 *bvci = ntohs(tlvp_val16_unal(&tp_inner, BSSGP_IE_BVCI));
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001022 else
1023 return -ENOENT;
1024
1025 return 0;
1026}
1027
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001028/* Receive an incoming signalling message from a BSS-side NS-VC */
Harald Weltee5209642020-12-05 19:59:45 +01001029static int gbprox_rx_sig_from_bss(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001030{
1031 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001032 uint8_t pdu_type = bgph->pdu_type;
Harald Weltee5209642020-12-05 19:59:45 +01001033 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
Philipp Maier74882dc2021-02-04 16:31:46 +01001034 struct tlv_parsed tp[2];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001035 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welte560bdb32020-12-04 22:24:47 +01001036 struct gbproxy_bvc *from_bvc = NULL;
Harald Welteec0f8012020-12-06 16:32:01 +01001037 char log_pfx[32];
Harald Weltee5209642020-12-05 19:59:45 +01001038 uint16_t ptp_bvci;
1039 uint32_t tlli;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001040 int rc;
1041
Harald Weltee5209642020-12-05 19:59:45 +01001042 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);
1043
1044 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welteec0f8012020-12-06 16:32:01 +01001045
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001046 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Weltee5209642020-12-05 19:59:45 +01001047 LOGP(DGPRS, LOGL_NOTICE, "%s %s BVCI=%05u is not signalling\n", log_pfx, pdut_name, ns_bvci);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001048 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001049 }
1050
Harald Welte278dd272020-12-06 13:35:24 +01001051 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Weltee5209642020-12-05 19:59:45 +01001052 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001053 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +01001054 }
1055
1056 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_UL)) {
Harald Weltee5209642020-12-05 19:59:45 +01001057 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001058 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001059 }
1060
Philipp Maier74882dc2021-02-04 16:31:46 +01001061 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp, ARRAY_SIZE(tp), pdu_type, bgph->data, data_len, 0, 0,
Harald Welteec0f8012020-12-06 16:32:01 +01001062 DGPRS, log_pfx);
1063 if (rc < 0) {
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001064 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_BSS));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001065 return tx_status_from_tlvp(nse, rc, msg);
Harald Welteec0f8012020-12-06 16:32:01 +01001066 }
Harald Weltee5209642020-12-05 19:59:45 +01001067 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
Philipp Maier74882dc2021-02-04 16:31:46 +01001068 msgb_bcid(msg) = (void *)tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001069
Harald Weltee5209642020-12-05 19:59:45 +01001070 /* special case handling for some PDU types */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001071 switch (pdu_type) {
Harald Weltee5209642020-12-05 19:59:45 +01001072 case BSSGP_PDUT_BVC_RESET:
1073 /* resolve or create gbproxy_bvc + handlei n BVC-FSM */
Philipp Maier74882dc2021-02-04 16:31:46 +01001074 return rx_bvc_reset_from_bss(nse, msg, &tp[0]);
Harald Weltee5209642020-12-05 19:59:45 +01001075 case BSSGP_PDUT_BVC_RESET_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001076 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001077 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
Harald Welte560bdb32020-12-04 22:24:47 +01001078 if (!from_bvc)
1079 goto err_no_bvc;
Harald Weltee5209642020-12-05 19:59:45 +01001080 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
1081 case BSSGP_PDUT_BVC_BLOCK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001082 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001083 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1084 if (!from_bvc)
1085 goto err_no_bvc;
1086 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK, msg);
1087 case BSSGP_PDUT_BVC_UNBLOCK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001088 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001089 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1090 if (!from_bvc)
1091 goto err_no_bvc;
1092 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK, msg);
1093 case BSSGP_PDUT_SUSPEND:
1094 case BSSGP_PDUT_RESUME:
Daniel Willmann77493b12020-12-29 21:13:31 +01001095 {
1096 struct gbproxy_sgsn *sgsn;
1097
Philipp Maier74882dc2021-02-04 16:31:46 +01001098 tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Daniel Willmann77493b12020-12-29 21:13:31 +01001099 sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
1100 if (!sgsn) {
1101 LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN for TLLI, dropping message!\n");
1102 rc = -EINVAL;
1103 break;
1104 }
1105
1106 gbproxy_tlli_cache_update(nse, tlli);
1107
1108 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
Harald Weltee5209642020-12-05 19:59:45 +01001109#if 0
1110 /* TODO: Validate the RAI for consistency with the RAI
1111 * we expect for any of the BVC within this BSS side NSE */
Philipp Maier74882dc2021-02-04 16:31:46 +01001112 memcpy(ra, TLVP_VAL(&tp[0], BSSGP_IE_ROUTEING_AREA), sizeof(from_bvc->ra));
Harald Welte560bdb32020-12-04 22:24:47 +01001113 gsm48_parse_ra(&raid, from_bvc->ra);
Harald Weltee5209642020-12-05 19:59:45 +01001114#endif
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001115 break;
Daniel Willmann77493b12020-12-29 21:13:31 +01001116 }
Harald Weltee5209642020-12-05 19:59:45 +01001117 case BSSGP_PDUT_STATUS:
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001118 {
1119 struct gbproxy_sgsn *sgsn;
1120 /* Check if the status needs to be terminated locally */
1121 uint8_t cause = *TLVP_VAL(&tp[0], BSSGP_IE_CAUSE);
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001122
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001123 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI || cause == BSSGP_CAUSE_BVCI_BLOCKED) {
1124 /* Log and handle locally */
1125 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001126 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s) for PtP-BVC %05u\n", cause,
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001127 bssgp_cause_str(cause), ptp_bvci);
1128 /* FIXME: Remove/block our BVC if present? */
1129 break;
1130 }
1131
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001132 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s) ", cause,
1133 bssgp_cause_str(cause));
1134
Daniel Willmann6ec5f952021-10-28 16:13:03 +02001135 if (gbproxy_tlli_from_status_pdu(tp, &tlli, log_pfx) == 0)
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001136 sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
1137 else
1138 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
1139
1140 if (!sgsn) {
1141 rc = -EINVAL;
1142 break;
1143 }
1144
1145 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
Harald Weltee5209642020-12-05 19:59:45 +01001146 break;
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001147 }
Harald Weltee5209642020-12-05 19:59:45 +01001148 case BSSGP_PDUT_RAN_INFO:
1149 case BSSGP_PDUT_RAN_INFO_REQ:
1150 case BSSGP_PDUT_RAN_INFO_ACK:
1151 case BSSGP_PDUT_RAN_INFO_ERROR:
1152 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
Philipp Maier1c5766b2021-02-09 17:03:03 +01001153 rc = gbprox_rx_rim_from_bss(tp, nse, msg, log_pfx, pdut_name);
Harald Weltee5209642020-12-05 19:59:45 +01001154 break;
1155 case BSSGP_PDUT_LLC_DISCARD:
Harald Weltee5209642020-12-05 19:59:45 +01001156 /* route based on BVCI + TLLI */
Philipp Maier74882dc2021-02-04 16:31:46 +01001157 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1158 tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Harald Weltee5209642020-12-05 19:59:45 +01001159 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1160 if (!from_bvc)
1161 goto err_no_bvc;
Daniel Willmanne705b3f2021-11-25 22:04:56 +01001162 rc = gbprox_bss2sgsn_tlli(from_bvc->cell, msg, &tlli, true);
Harald Weltee5209642020-12-05 19:59:45 +01001163 break;
Daniel Willmanne705b3f2021-11-25 22:04:56 +01001164 case BSSGP_PDUT_FLUSH_LL_ACK:
1165 {
1166 /* Route based on TLLI */
1167 tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
1168 struct gbproxy_sgsn *sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
1169 if (!sgsn) {
1170 rc = -EINVAL;
1171 break;
1172 }
1173
1174 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
1175 break;
1176 }
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001177 case BSSGP_PDUT_PAGING_PS_REJECT:
Daniel Willmann5614e572021-01-18 18:38:27 +01001178 case BSSGP_PDUT_DUMMY_PAGING_PS_RESP:
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001179 {
1180 /* Route according to IMSI<->NSE cache entry */
1181 struct osmo_mobile_identity mi;
Philipp Maier74882dc2021-02-04 16:31:46 +01001182 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1183 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001184 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +02001185 nse = gbproxy_nse_by_imsi(nse->cfg, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001186 if (!nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001187 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001188 }
Daniel Willmann5614e572021-01-18 18:38:27 +01001189 OSMO_ASSERT(nse->sgsn_facing);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001190 rc = gbprox_relay2nse(msg, nse, 0);
1191 break;
1192 }
Daniel Willmannf024eeb2021-07-06 14:02:41 +02001193 case BSSGP_PDUT_MS_REGISTR_ENQ:
1194 {
1195 struct gbproxy_sgsn *sgsn;
1196 struct osmo_mobile_identity mi;
1197 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1198 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
1199 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
1200
1201 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
1202 if (!sgsn) {
1203 LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN, dropping message!\n");
1204 rc = -EINVAL;
1205 break;
1206 }
1207
1208 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1209
1210 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
1211 break;
1212 }
Harald Weltee5209642020-12-05 19:59:45 +01001213 default:
1214 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001215 break;
1216 }
1217
Harald Weltee5209642020-12-05 19:59:45 +01001218 return rc;
Harald Welte560bdb32020-12-04 22:24:47 +01001219err_no_bvc:
Harald Weltee5209642020-12-05 19:59:45 +01001220 LOGPNSE(nse, LOGL_ERROR, "Rx %s: cannot find BVC for BVCI=%05u\n", pdut_name, ptp_bvci);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001221 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_NSEI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001222 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001223}
1224
1225/* Receive paging request from SGSN, we need to relay to proper BSS */
Harald Weltedf690e82020-12-12 15:58:28 +01001226static int gbprox_rx_paging(struct gbproxy_nse *sgsn_nse, struct msgb *msg, const char *pdut_name,
Daniel Willmann5614e572021-01-18 18:38:27 +01001227 struct tlv_parsed *tp, uint16_t ns_bvci, bool broadcast)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001228{
Harald Weltedf690e82020-12-12 15:58:28 +01001229 struct gbproxy_config *cfg = sgsn_nse->cfg;
Harald Weltee5209642020-12-05 19:59:45 +01001230 struct gbproxy_bvc *sgsn_bvc, *bss_bvc;
Harald Weltedf690e82020-12-12 15:58:28 +01001231 struct gbproxy_nse *nse;
Daniel Willmann76205712020-11-30 17:08:58 +01001232 unsigned int n_nses = 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001233 int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
Harald Welte8b4c7942020-12-05 10:14:49 +01001234 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001235
Harald Welte173a1822020-12-03 15:36:59 +01001236 if (TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001237 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001238 errctr = GBPROX_GLOB_CTR_OTHER_ERR;
Harald Weltedf690e82020-12-12 15:58:28 +01001239 sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
Harald Weltee5209642020-12-05 19:59:45 +01001240 if (!sgsn_bvc) {
Harald Weltedf690e82020-12-12 15:58:28 +01001241 LOGPNSE(sgsn_nse, LOGL_NOTICE, "Rx %s: unable to route: BVCI=%05u unknown\n",
Harald Weltee5209642020-12-05 19:59:45 +01001242 pdut_name, bvci);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001243 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001244 return -EINVAL;
1245 }
Harald Weltee5209642020-12-05 19:59:45 +01001246 LOGPBVC(sgsn_bvc, LOGL_INFO, "Rx %s: routing by BVCI\n", pdut_name);
1247 return gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Harald Welte173a1822020-12-03 15:36:59 +01001248 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {
Philipp Maierda3af942021-02-04 21:54:09 +01001249 struct gprs_ra_id raid;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001250 errctr = GBPROX_GLOB_CTR_INV_RAI;
Philipp Maierda3af942021-02-04 21:54:09 +01001251 gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
Harald Welte560bdb32020-12-04 22:24:47 +01001252 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001253 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001254 hash_for_each(nse->bvcs, j, bss_bvc, list) {
Daniel Willmannf9902c52021-11-12 15:52:03 +01001255 /* Skip BVCs without a cell (e.g. signalling) */
1256 if (!bss_bvc->cell)
1257 continue;
1258
1259 if (gsm48_ra_equal(&bss_bvc->cell->id.raid, &raid)) {
Harald Weltee5209642020-12-05 19:59:45 +01001260 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (RAI match)\n",
1261 pdut_name);
1262 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001263 n_nses++;
1264 /* Only send it once to each NSE */
1265 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001266 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001267 }
1268 }
Harald Welte173a1822020-12-03 15:36:59 +01001269 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_LOCATION_AREA, 5)) {
Philipp Maierda3af942021-02-04 21:54:09 +01001270 struct gsm48_ra_id lac;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001271 errctr = GBPROX_GLOB_CTR_INV_LAI;
Harald Welte560bdb32020-12-04 22:24:47 +01001272 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001273 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001274 hash_for_each(nse->bvcs, j, bss_bvc, list) {
Daniel Willmannf9902c52021-11-12 15:52:03 +01001275 /* Skip BVCs without a cell (e.g. signalling) */
1276 if (!bss_bvc->cell)
1277 continue;
1278
1279 gsm48_encode_ra(&lac, &bss_bvc->cell->id.raid);
Philipp Maierda3af942021-02-04 21:54:09 +01001280 if (!memcmp(&lac, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
Harald Weltee5209642020-12-05 19:59:45 +01001281 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (LAI match)\n",
1282 pdut_name);
1283 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001284 n_nses++;
1285 /* Only send it once to each NSE */
1286 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001287 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001288 }
1289 }
Daniel Willmann5614e572021-01-18 18:38:27 +01001290 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1) || broadcast) {
Harald Welte560bdb32020-12-04 22:24:47 +01001291 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001292 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001293 hash_for_each(nse->bvcs, j, bss_bvc, list) {
1294 LOGPNSE(nse, LOGL_INFO, "Rx %s:routing to NSE (broadcast)\n", pdut_name);
1295 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001296 n_nses++;
1297 /* Only send it once to each NSE */
1298 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001299 }
Harald Welte53ee2062020-11-24 11:31:13 +01001300 }
1301 } else {
Harald Weltedf690e82020-12-12 15:58:28 +01001302 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, missing IE\n");
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001303 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Harald Welte53ee2062020-11-24 11:31:13 +01001304 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001305
Daniel Willmann76205712020-11-30 17:08:58 +01001306 if (n_nses == 0) {
Harald Weltedf690e82020-12-12 15:58:28 +01001307 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, no destination found\n");
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001308 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001309 return -EINVAL;
1310 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001311 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001312}
1313
1314/* Receive an incoming BVC-RESET message from the SGSN */
Harald Weltee5209642020-12-05 19:59:45 +01001315static int rx_bvc_reset_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp,
1316 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001317{
Harald Weltee5209642020-12-05 19:59:45 +01001318 uint16_t ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
1319 struct gbproxy_bvc *from_bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001320
Harald Weltee5209642020-12-05 19:59:45 +01001321 LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", ptp_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001322
Harald Weltee5209642020-12-05 19:59:45 +01001323 if (ptp_bvci == 0) {
1324 from_bvc = gbproxy_bvc_by_bvci(nse, 0);
1325 OSMO_ASSERT(from_bvc);
1326 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
1327 } else {
1328 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1329 if (!from_bvc) {
1330 LOGPNSE(nse, LOGL_ERROR, "Rx BVC-RESET BVCI=%05u: Cannot find BVC\n", ptp_bvci);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001331 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001332 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKNOWN_BVCI, &ptp_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001333 }
Harald Weltee5209642020-12-05 19:59:45 +01001334 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
Daniel Willmanne50550e2020-11-26 18:19:21 +01001335 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001336
1337 return 0;
1338}
1339
Philipp Maier1c5766b2021-02-09 17:03:03 +01001340/* Receive an incoming RIM message from the SGSN-side NS-VC */
1341static int gbprox_rx_rim_from_sgsn(struct tlv_parsed *tp, struct gbproxy_nse *nse, struct msgb *msg, char *log_pfx,
1342 const char *pdut_name)
1343{
1344 struct gbproxy_sgsn *sgsn;
1345 struct gbproxy_cell *dest_cell;
1346 struct bssgp_rim_routing_info dest_ri;
1347 struct bssgp_rim_routing_info src_ri;
1348 int rc;
Philipp Maier4499cf42021-02-10 17:54:44 +01001349 char ri_src_str[64];
1350 char ri_dest_str[64];
Daniel Willmannf8cba652021-02-12 04:59:47 +01001351 uint16_t ns_bvci = msgb_bvci(msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001352
1353 /* TODO: Reply with STATUS if BSSGP didn't negotiate RIM feature, see also comments in
1354 gbprox_rx_rim_from_bss() */
1355
1356 rc = bssgp_parse_rim_ri(&dest_ri, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
1357 TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
1358 if (rc < 0) {
1359 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse destination RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001360 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001361 }
1362 rc = bssgp_parse_rim_ri(&src_ri, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
1363 TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
1364 if (rc < 0) {
1365 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse source RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001366 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001367 }
1368
1369 /* Since gbproxy is 2G only we do not expect to get RIM messages that target non-GERAN cells. */
1370 if (dest_ri.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
1371 LOGP(DGPRS, LOGL_ERROR, "%s %s destination RIM routing info is not GERAN (%s)\n", log_pfx, pdut_name,
1372 bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001373 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001374 }
1375
1376 /* Lookup destination cell */
1377 dest_cell = gbproxy_cell_by_cellid(nse->cfg, &dest_ri.geran.raid, dest_ri.geran.cid);
1378 if (!dest_cell) {
1379 LOGP(DGPRS, LOGL_NOTICE, "%s %s cannot find cell for destination RIM routing info (%s)\n", log_pfx,
1380 pdut_name, bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001381 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001382 }
1383
1384 /* TODO: Check if the BVC of the destination cell actually did negotiate RIM support, see also comments
1385 * in gbprox_rx_rim_from_bss() */
1386 sgsn = gbproxy_sgsn_by_nsei(nse->cfg, nse->nsei);
1387 OSMO_ASSERT(sgsn);
1388
Philipp Maier4499cf42021-02-10 17:54:44 +01001389 LOGP(DLBSSGP, LOGL_DEBUG, "%s %s relaying from SGSN(%05u/%s) RIM-PDU: src=%s, dest=%s\n",
1390 log_pfx, pdut_name, sgsn->nse->nsei, sgsn->name,
1391 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &src_ri),
1392 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &dest_ri));
Philipp Maier1c5766b2021-02-09 17:03:03 +01001393
1394 return gbprox_relay2peer(msg, dest_cell->bss_bvc, 0);
1395}
1396
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001397/* Receive an incoming signalling message from the SGSN-side NS-VC */
Harald Weltedbef0aa2020-12-07 17:48:11 +01001398static int gbprox_rx_sig_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001399{
Harald Weltedbef0aa2020-12-07 17:48:11 +01001400 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001401 uint8_t pdu_type = bgph->pdu_type;
Harald Weltee5209642020-12-05 19:59:45 +01001402 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
1403 struct gbproxy_config *cfg = nse->cfg;
1404 struct gbproxy_bvc *sgsn_bvc;
Philipp Maier74882dc2021-02-04 16:31:46 +01001405 struct tlv_parsed tp[2];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001406 int data_len;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001407 uint16_t bvci;
Harald Welteec0f8012020-12-06 16:32:01 +01001408 char log_pfx[32];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001409 int rc = 0;
Harald Welted2fef952020-12-05 00:31:07 +01001410 int i;
Daniel Willmann5614e572021-01-18 18:38:27 +01001411 bool paging_bc = false;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001412
Harald Weltee5209642020-12-05 19:59:45 +01001413 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);
1414
1415 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welteec0f8012020-12-06 16:32:01 +01001416
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001417 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welteec0f8012020-12-06 16:32:01 +01001418 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001419 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001420 }
1421
Harald Welte278dd272020-12-06 13:35:24 +01001422 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Weltee5209642020-12-05 19:59:45 +01001423 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001424 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +01001425 }
1426
1427 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_DL)) {
Harald Weltee5209642020-12-05 19:59:45 +01001428 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001429 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001430 }
1431
Harald Weltedbef0aa2020-12-07 17:48:11 +01001432 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welteec0f8012020-12-06 16:32:01 +01001433
Philipp Maier74882dc2021-02-04 16:31:46 +01001434 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp, ARRAY_SIZE(tp), pdu_type, bgph->data, data_len, 0, 0,
Harald Welteec0f8012020-12-06 16:32:01 +01001435 DGPRS, log_pfx);
1436 if (rc < 0) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001437 rc = tx_status_from_tlvp(nse, rc, msg);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001438 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_SGSN));
Harald Welteec0f8012020-12-06 16:32:01 +01001439 return rc;
1440 }
Harald Weltee5209642020-12-05 19:59:45 +01001441 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
Philipp Maier74882dc2021-02-04 16:31:46 +01001442 msgb_bcid(msg) = (void *)tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001443
1444 switch (pdu_type) {
1445 case BSSGP_PDUT_BVC_RESET:
Harald Weltee5209642020-12-05 19:59:45 +01001446 /* resolve or create ggbproxy_bvc + handle in BVC-FSM */
Philipp Maier74882dc2021-02-04 16:31:46 +01001447 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1448 rc = rx_bvc_reset_from_sgsn(nse, msg, &tp[0], ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001449 break;
1450 case BSSGP_PDUT_BVC_RESET_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001451 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001452 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1453 if (!sgsn_bvc)
1454 goto err_no_bvc;
1455 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
1456 break;
1457 case BSSGP_PDUT_BVC_BLOCK_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001458 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001459 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
Daniel Willmanndc763fd2021-09-24 16:45:38 +02001460 if (!sgsn_bvc) {
1461 /* Check if BVC was blocked before */
1462 sgsn_bvc = gbproxy_bvc_by_bvci_inactive(nse, bvci);
1463 if (!sgsn_bvc)
1464 goto err_no_bvc;
1465 }
Harald Weltee5209642020-12-05 19:59:45 +01001466 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK_ACK, msg);
1467 break;
1468 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001469 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001470 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1471 if (!sgsn_bvc)
1472 goto err_no_bvc;
1473 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK_ACK, msg);
Daniel Willmann8489e7a2020-11-03 21:12:42 +01001474 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001475 case BSSGP_PDUT_FLUSH_LL:
Daniel Willmanne705b3f2021-11-25 22:04:56 +01001476 /* TODO: If new BVCI is on different NSE we should remove the new BVCI so the
1477 * message is interpreted as a request to delete the PDUs, not forward them.
1478 * If we negotiate Inter-NSE re-routing or LCS-procedures we can also
1479 * add the NSEI TLV to trigger re-routing the PDUs */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001480 /* simple case: BVCI IE is mandatory */
Philipp Maier74882dc2021-02-04 16:31:46 +01001481 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001482 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1483 if (!sgsn_bvc)
1484 goto err_no_bvc;
1485 if (sgsn_bvc->cell && sgsn_bvc->cell->bss_bvc)
1486 rc = gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001487 break;
Daniel Willmann5614e572021-01-18 18:38:27 +01001488 case BSSGP_PDUT_DUMMY_PAGING_PS:
1489 /* Routing area is optional in dummy paging and we have nothing else to go by
1490 * so in case it is missing we need to broadcast the paging */
1491 paging_bc = true;
1492 /* fall through */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001493 case BSSGP_PDUT_PAGING_PS:
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001494 {
1495 /* Cache the IMSI<->NSE to route PAGING REJECT */
1496 struct osmo_mobile_identity mi;
Philipp Maier74882dc2021-02-04 16:31:46 +01001497 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1498 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001499 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +02001500 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001501 /* fall through */
1502 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001503 case BSSGP_PDUT_PAGING_CS:
1504 /* process the paging request (LAI/RAI lookup) */
Philipp Maier74882dc2021-02-04 16:31:46 +01001505 rc = gbprox_rx_paging(nse, msg, pdut_name, &tp[0], ns_bvci, paging_bc);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001506 break;
1507 case BSSGP_PDUT_STATUS:
Daniel Willmann885f4302021-09-30 16:58:46 +02001508 {
1509 struct gbproxy_nse *nse_peer;
1510 uint32_t tlli;
1511
1512 /* Check if the status needs to be terminated locally */
1513 uint8_t cause = *TLVP_VAL(&tp[0], BSSGP_IE_CAUSE);
1514
1515 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI || cause == BSSGP_CAUSE_BVCI_BLOCKED) {
1516 /* Log and handle locally, BVCI should be present for these causes */
1517 if (!TLVP_PRESENT(&tp[0], BSSGP_IE_BVCI)) {
1518 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s), but BVCI is missing\n", cause,
1519 bssgp_cause_str(cause));
1520 break;
1521 }
1522 uint16_t ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1523 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s) for PtP-BVC %05u\n", cause,
1524 bssgp_cause_str(cause), ptp_bvci);
1525 /* FIXME: Remove/block the other BSS/SGSN BVCs if present? */
1526 break;
1527 }
1528
1529 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s)\n", cause,
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001530 bssgp_cause_str(cause));
Daniel Willmann885f4302021-09-30 16:58:46 +02001531
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001532
1533 if (gbproxy_bvci_from_status_pdu(tp, &bvci, log_pfx) == 0 && bvci != 0) {
1534 struct gbproxy_cell *cell = gbproxy_cell_by_bvci(cfg, bvci);
1535
1536 if ((!cell || !cell->bss_bvc || !cell->bss_bvc->nse)) {
1537 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s), but can't find NSE for cell\n",
1538 cause, bssgp_cause_str(cause));
1539 break;
1540 }
1541
1542 return gbprox_relay2nse(msg, cell->bss_bvc->nse, 0);
1543 }
1544
Daniel Willmann6ec5f952021-10-28 16:13:03 +02001545 /* We can only forward this TLLI if it's in the cache (which only happens on suspend/resume) */
1546 if (gbproxy_tlli_from_status_pdu(tp, &tlli, log_pfx) == 0) {
Daniel Willmann885f4302021-09-30 16:58:46 +02001547 nse_peer = gbproxy_nse_by_tlli(cfg, tlli);
1548 if (nse_peer)
1549 return gbprox_relay2nse(msg, nse_peer, 0);
1550 }
1551
1552 LOGPNSE(nse, LOGL_ERROR, "Unable to handle STATUS cause=0x%02x(%s)\n", cause,
1553 bssgp_cause_str(cause));
1554
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001555 break;
Daniel Willmann885f4302021-09-30 16:58:46 +02001556 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001557 /* those only exist in the SGSN -> BSS direction */
1558 case BSSGP_PDUT_SUSPEND_ACK:
1559 case BSSGP_PDUT_SUSPEND_NACK:
1560 case BSSGP_PDUT_RESUME_ACK:
1561 case BSSGP_PDUT_RESUME_NACK:
Daniel Willmann77493b12020-12-29 21:13:31 +01001562 {
1563 struct gbproxy_nse *nse_peer;
Philipp Maier74882dc2021-02-04 16:31:46 +01001564 uint32_t tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Daniel Willmann77493b12020-12-29 21:13:31 +01001565
1566 nse_peer = gbproxy_nse_by_tlli(cfg, tlli);
1567 if (!nse_peer) {
1568 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);
1569 /* TODO: Counter */
Daniel Willmannf8cba652021-02-12 04:59:47 +01001570 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Daniel Willmann77493b12020-12-29 21:13:31 +01001571 }
1572 /* Delete the entry after we're done */
1573 gbproxy_tlli_cache_remove(cfg, tlli);
1574 LOGPNSE(nse_peer, LOGL_DEBUG, "Rx %s: forwarding\n", pdut_name);
1575 gbprox_relay2nse(msg, nse_peer, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001576 break;
Daniel Willmann77493b12020-12-29 21:13:31 +01001577 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001578 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
Harald Welte7479c4d2020-12-02 20:06:04 +01001579 case BSSGP_PDUT_OVERLOAD:
Harald Weltee5209642020-12-05 19:59:45 +01001580 LOGPNSE(nse, LOGL_DEBUG, "Rx %s: broadcasting\n", pdut_name);
Harald Welte560bdb32020-12-04 22:24:47 +01001581 /* broadcast to all BSS-side bvcs */
Harald Welted2fef952020-12-05 00:31:07 +01001582 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte7479c4d2020-12-02 20:06:04 +01001583 gbprox_relay2nse(msg, nse, 0);
1584 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001585 break;
Harald Weltee5209642020-12-05 19:59:45 +01001586 case BSSGP_PDUT_RAN_INFO:
1587 case BSSGP_PDUT_RAN_INFO_REQ:
1588 case BSSGP_PDUT_RAN_INFO_ACK:
1589 case BSSGP_PDUT_RAN_INFO_ERROR:
1590 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
Philipp Maier1c5766b2021-02-09 17:03:03 +01001591 rc = gbprox_rx_rim_from_sgsn(tp, nse, msg, log_pfx, pdut_name);
Pau Espin Pedrola4296342021-05-07 13:33:34 +02001592 break;
Daniel Willmannf024eeb2021-07-06 14:02:41 +02001593 case BSSGP_PDUT_MS_REGISTR_ENQ_RESP:
1594 {
1595 struct gbproxy_nse *nse_peer;
1596 struct osmo_mobile_identity mi;
1597 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1598 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
1599 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
1600 nse_peer = gbproxy_nse_by_imsi(cfg, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1601 if (!nse_peer) {
1602 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);
1603 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
1604 } else if (nse_peer->sgsn_facing) {
1605 LOGPNSE(nse, LOGL_ERROR, "Forwarding %s failed: IMSI cache contains SGSN NSE", pdut_name);
1606 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
1607 }
1608 gbproxy_imsi_cache_remove(cfg, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1609 gbprox_relay2nse(msg, nse_peer, ns_bvci);
1610 break;
1611 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001612 default:
Harald Weltee5209642020-12-05 19:59:45 +01001613 LOGPNSE(nse, LOGL_NOTICE, "Rx %s: Not supported\n", pdut_name);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001614 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_SGSN));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001615 rc = tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001616 break;
1617 }
1618
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001619 return rc;
Harald Weltee5209642020-12-05 19:59:45 +01001620
Harald Welte560bdb32020-12-04 22:24:47 +01001621err_no_bvc:
Daniel Willmann723bb362021-09-28 18:51:47 +02001622 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find BVC %05u\n", pdut_name, bvci);
Daniel Willmannc4b913b2021-09-24 16:43:42 +02001623 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001624 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001625}
1626
Harald Weltee5209642020-12-05 19:59:45 +01001627
1628/***********************************************************************
1629 * libosmogb NS/BSSGP integration
1630 ***********************************************************************/
1631
Alexander Couzens951e1332020-09-22 13:21:46 +02001632int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001633{
1634 int rc;
Alexander Couzens951e1332020-09-22 13:21:46 +02001635 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
1636 struct gprs_ns2_inst *nsi = cfg->nsi;
1637 struct osmo_gprs_ns2_prim nsp = {};
1638
1639 nsp.bvci = msgb_bvci(msg);
1640 nsp.nsei = msgb_nsei(msg);
1641
Alexander Couzens55c36f92021-01-27 20:56:55 +01001642 osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
Alexander Couzens951e1332020-09-22 13:21:46 +02001643 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
1644
1645 return rc;
1646}
1647
1648/* Main input function for Gb proxy */
1649int gbprox_rcvmsg(void *ctx, struct msgb *msg)
1650{
Alexander Couzens951e1332020-09-22 13:21:46 +02001651 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Harald Weltee5209642020-12-05 19:59:45 +01001652 uint16_t ns_bvci = msgb_bvci(msg);
1653 uint16_t nsei = msgb_nsei(msg);
1654 struct gbproxy_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001655
Harald Weltee5209642020-12-05 19:59:45 +01001656 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_SGSN);
1657 if (nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001658 /* ensure minimum length to decode PDU type */
1659 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
1660 return tx_status(nse, ns_bvci, BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
1661
Harald Weltee5209642020-12-05 19:59:45 +01001662 if (ns_bvci == 0 || ns_bvci == 1)
1663 return gbprox_rx_sig_from_sgsn(nse, msg, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001664 else
Harald Weltee5209642020-12-05 19:59:45 +01001665 return gbprox_rx_ptp_from_sgsn(nse, msg, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001666 }
1667
Harald Weltee5209642020-12-05 19:59:45 +01001668 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_BSS);
1669 if (!nse) {
1670 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) not known -> allocating\n", nsei);
1671 nse = gbproxy_nse_alloc(cfg, nsei, false);
1672 }
1673 if (nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001674 /* ensure minimum length to decode PDU type */
1675 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
1676 return tx_status(nse, ns_bvci, BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
1677
Harald Weltee5209642020-12-05 19:59:45 +01001678 if (ns_bvci == 0 || ns_bvci == 1)
1679 return gbprox_rx_sig_from_bss(nse, msg, ns_bvci);
1680 else
1681 return gbprox_rx_ptp_from_bss(nse, msg, ns_bvci);
1682 }
1683
1684 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001685}
1686
Alexander Couzens951e1332020-09-22 13:21:46 +02001687/* TODO: What about handling:
Alexander Couzens55c36f92021-01-27 20:56:55 +01001688 * GPRS_NS2_AFF_CAUSE_VC_FAILURE,
1689 GPRS_NS2_AFF_CAUSE_VC_RECOVERY,
Alexander Couzens951e1332020-09-22 13:21:46 +02001690 osmocom own causes
Alexander Couzens55c36f92021-01-27 20:56:55 +01001691 GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED,
1692 GPRS_NS2_AFF_CAUSE_SNS_FAILURE,
Alexander Couzens951e1332020-09-22 13:21:46 +02001693 */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001694
Alexander Couzens951e1332020-09-22 13:21:46 +02001695void gprs_ns_prim_status_cb(struct gbproxy_config *cfg, struct osmo_gprs_ns2_prim *nsp)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001696{
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001697 int i;
Harald Welte560bdb32020-12-04 22:24:47 +01001698 struct gbproxy_bvc *bvc;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001699 struct gbproxy_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001700
Alexander Couzens951e1332020-09-22 13:21:46 +02001701 switch (nsp->u.status.cause) {
Alexander Couzens55c36f92021-01-27 20:56:55 +01001702 case GPRS_NS2_AFF_CAUSE_SNS_FAILURE:
1703 case GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED:
Alexander Couzens951e1332020-09-22 13:21:46 +02001704 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001705
Alexander Couzens55c36f92021-01-27 20:56:55 +01001706 case GPRS_NS2_AFF_CAUSE_RECOVERY:
Harald Welte9b367d22021-01-18 13:55:51 +01001707 LOGP(DGPRS, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);
Daniel Willmannf96cac52021-03-09 16:14:18 +01001708 nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_SGSN);
1709 if (nse) {
Daniel Willmann37518b32021-05-27 18:13:36 +02001710 nse->alive = true;
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001711 // Update the NSE max SDU len
Daniel Willmannf96cac52021-03-09 16:14:18 +01001712 nse->max_sdu_len = nsp->u.status.mtu;
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001713
Harald Weltee5209642020-12-05 19:59:45 +01001714 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001715 bvc = gbproxy_bvc_by_bvci(nse, 0);
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001716 if (bvc) {
Daniel Willmannf96cac52021-03-09 16:14:18 +01001717 bssgp_bvc_fsm_set_max_pdu_len(bvc->fi, nse->max_sdu_len);
Daniel Willmann3ea37932021-02-10 13:41:14 +01001718 osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001719 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001720 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001721 break;
Alexander Couzens55c36f92021-01-27 20:56:55 +01001722 case GPRS_NS2_AFF_CAUSE_FAILURE:
Daniel Willmannf96cac52021-03-09 16:14:18 +01001723 nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_BSS | NSE_F_SGSN);
1724 if (!nse) {
1725 LOGP(DGPRS, LOGL_ERROR, "Unknown NSE(%05d) became unavailable\n", nsp->nsei);
1726 break;
1727 }
Daniel Willmann37518b32021-05-27 18:13:36 +02001728
1729 nse->alive = false;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001730 if (nse->sgsn_facing) {
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001731 struct hlist_node *ntmp;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001732 /* SGSN */
1733 /* TODO: When to block all PtP towards bss? Only if all SGSN are down? */
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001734 hash_for_each_safe(nse->bvcs, i, ntmp, bvc, list) {
1735 if (bvc->bvci == 0)
1736 continue;
1737 gbproxy_bvc_free(bvc);
1738 }
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001739 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_RESTART_RESET_SGSN));
Alexander Couzens951e1332020-09-22 13:21:46 +02001740 } else {
Daniel Willmannf96cac52021-03-09 16:14:18 +01001741 /* BSS became unavailable
1742 * Block matching PtP-BVCs on SGSN-side */
1743 hash_for_each(nse->bvcs, i, bvc, list) {
1744 if (bvc->bvci == 0)
1745 continue;
1746 /* Get BVC for each SGSN and send block request */
1747 struct gbproxy_cell *cell = bvc->cell;
1748 for (int j = 0; j < GBPROXY_MAX_NR_SGSN; j++) {
1749 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[j];
1750 if (!sgsn_bvc)
1751 continue;
1752
1753 /* Block BVC, indicate BSS equipment failure */
1754 uint8_t cause = BSSGP_CAUSE_EQUIP_FAIL;
1755 osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
Daniel Willmanndc763fd2021-09-24 16:45:38 +02001756 sgsn_bvc->inactive = true;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001757 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001758 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001759
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001760 /* This frees the BVCs for us as well */
1761 gbproxy_nse_free(nse);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001762 }
Harald Welte9b367d22021-01-18 13:55:51 +01001763 LOGP(DGPRS, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);
Alexander Couzens951e1332020-09-22 13:21:46 +02001764 break;
1765 default:
Harald Welte9b367d22021-01-18 13:55:51 +01001766 LOGP(DGPRS, LOGL_NOTICE, "NS: Unknown NS-STATUS.ind cause=%s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001767 gprs_ns2_aff_cause_prim_str(nsp->u.status.cause));
Alexander Couzens951e1332020-09-22 13:21:46 +02001768 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001769 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001770}
1771
Alexander Couzens951e1332020-09-22 13:21:46 +02001772/* called by the ns layer */
1773int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
1774{
1775 struct osmo_gprs_ns2_prim *nsp;
1776 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Daniel Willmann8f407b12020-12-02 19:33:50 +01001777 uintptr_t bvci;
Alexander Couzens951e1332020-09-22 13:21:46 +02001778 int rc = 0;
1779
1780 if (oph->sap != SAP_NS)
1781 return 0;
1782
1783 nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
1784
1785 if (oph->operation != PRIM_OP_INDICATION) {
Harald Welte9b367d22021-01-18 13:55:51 +01001786 LOGP(DGPRS, LOGL_NOTICE, "NS: Unexpected primitive operation %s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001787 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +02001788 return 0;
1789 }
1790
1791 switch (oph->primitive) {
Alexander Couzens55c36f92021-01-27 20:56:55 +01001792 case GPRS_NS2_PRIM_UNIT_DATA:
Daniel Willmann8f407b12020-12-02 19:33:50 +01001793
Alexander Couzens951e1332020-09-22 13:21:46 +02001794 /* hand the message into the BSSGP implementation */
1795 msgb_bssgph(oph->msg) = oph->msg->l3h;
1796 msgb_bvci(oph->msg) = nsp->bvci;
1797 msgb_nsei(oph->msg) = nsp->nsei;
Daniel Willmann8f407b12020-12-02 19:33:50 +01001798 bvci = nsp->bvci | BVC_LOG_CTX_FLAG;
Alexander Couzens951e1332020-09-22 13:21:46 +02001799
Daniel Willmann8f407b12020-12-02 19:33:50 +01001800 log_set_context(LOG_CTX_GB_BVC, (void *)bvci);
Alexander Couzens951e1332020-09-22 13:21:46 +02001801 rc = gbprox_rcvmsg(cfg, oph->msg);
Daniel Willmannb6550102020-11-04 17:32:56 +01001802 msgb_free(oph->msg);
Alexander Couzens951e1332020-09-22 13:21:46 +02001803 break;
Alexander Couzens55c36f92021-01-27 20:56:55 +01001804 case GPRS_NS2_PRIM_STATUS:
Alexander Couzens951e1332020-09-22 13:21:46 +02001805 gprs_ns_prim_status_cb(cfg, nsp);
1806 break;
1807 default:
Harald Welte9b367d22021-01-18 13:55:51 +01001808 LOGP(DGPRS, LOGL_NOTICE, "NS: Unknown prim %s %s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001809 gprs_ns2_prim_str(oph->primitive),
1810 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +02001811 break;
1812 }
1813
1814 return rc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001815}
1816
1817void gbprox_reset(struct gbproxy_config *cfg)
1818{
Harald Welted2fef952020-12-05 00:31:07 +01001819 struct gbproxy_nse *nse;
1820 struct hlist_node *ntmp;
Harald Welte8b4c7942020-12-05 10:14:49 +01001821 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001822
Harald Welted2fef952020-12-05 00:31:07 +01001823 hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +01001824 struct gbproxy_bvc *bvc;
1825 struct hlist_node *tmp;
1826 hash_for_each_safe(nse->bvcs, j, tmp, bvc, list)
Harald Welte560bdb32020-12-04 22:24:47 +01001827 gbproxy_bvc_free(bvc);
Daniel Willmanne50550e2020-11-26 18:19:21 +01001828
1829 gbproxy_nse_free(nse);
1830 }
Harald Weltee5209642020-12-05 19:59:45 +01001831 /* FIXME: cells */
1832 /* FIXME: SGSN side BVCs (except signaling) */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001833
1834 rate_ctr_group_free(cfg->ctrg);
1835 gbproxy_init_config(cfg);
1836}
1837
Daniel Willmann77493b12020-12-29 21:13:31 +01001838static void tlli_cache_cleanup(void *data)
1839{
1840 struct gbproxy_config *cfg = data;
1841 gbproxy_tlli_cache_cleanup(cfg);
1842
1843 /* TODO: Disable timer when cache is empty */
1844 osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);
1845}
1846
Daniel Willmannc8a50092021-01-17 13:11:41 +01001847static void imsi_cache_cleanup(void *data)
1848{
1849 struct gbproxy_config *cfg = data;
1850 gbproxy_imsi_cache_cleanup(cfg);
1851
1852 /* TODO: Disable timer when cache is empty */
1853 osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0);
1854}
1855
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001856int gbproxy_init_config(struct gbproxy_config *cfg)
1857{
1858 struct timespec tp;
1859
Harald Welte209dc9f2020-12-12 19:02:16 +01001860 /* by default we advertise 100% of the BSS-side capacity to _each_ SGSN */
1861 cfg->pool.bvc_fc_ratio = 100;
Daniel Willmannee834af2020-12-14 16:22:39 +01001862 cfg->pool.null_nri_ranges = osmo_nri_ranges_alloc(cfg);
Daniel Willmann77493b12020-12-29 21:13:31 +01001863 /* TODO: Make configurable */
Daniel Willmannbd12f3f2021-01-13 18:16:04 +01001864 cfg->tlli_cache.timeout = 10;
Daniel Willmannc8a50092021-01-17 13:11:41 +01001865 cfg->imsi_cache.timeout = 10;
Daniel Willmannee834af2020-12-14 16:22:39 +01001866
Harald Welted2fef952020-12-05 00:31:07 +01001867 hash_init(cfg->bss_nses);
Daniel Willmann1e7be5d2020-12-21 18:08:21 +01001868 hash_init(cfg->sgsn_nses);
1869 hash_init(cfg->cells);
Daniel Willmann77493b12020-12-29 21:13:31 +01001870 hash_init(cfg->tlli_cache.entries);
Daniel Willmannee834af2020-12-14 16:22:39 +01001871 INIT_LLIST_HEAD(&cfg->sgsns);
1872
Daniel Willmann77493b12020-12-29 21:13:31 +01001873 osmo_timer_setup(&cfg->tlli_cache.timer, tlli_cache_cleanup, cfg);
1874 osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);
1875
Daniel Willmannc8a50092021-01-17 13:11:41 +01001876 /* We could also combine both timers */
1877 osmo_timer_setup(&cfg->imsi_cache.timer, imsi_cache_cleanup, cfg);
1878 osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0);
1879
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001880 cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
1881 if (!cfg->ctrg) {
1882 LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
1883 return -1;
1884 }
1885 osmo_clock_gettime(CLOCK_REALTIME, &tp);
Harald Weltec169de42020-12-07 13:12:13 +01001886 osmo_fsm_log_timeouts(true);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001887
1888 return 0;
Oliver Smith29532c22021-01-29 11:13:00 +01001889}