blob: 18e0efb20b86db42bfeba81f5e154c4af50f5a7b [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
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200383/* Receive an incoming PTP message from a BSS-side NS-VC */
Harald Weltee5209642020-12-05 19:59:45 +0100384static 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 +0200385{
Harald Welte278dd272020-12-06 13:35:24 +0100386 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Weltee5209642020-12-05 19:59:45 +0100387 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
388 struct gbproxy_bvc *bss_bvc;
389 struct tlv_parsed tp;
390 char log_pfx[32];
391 uint32_t tlli;
392 int rc;
393
394 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);
395
396 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200397
Daniel Willmann06331ac2020-12-10 17:59:46 +0100398 if (ns_bvci == 0 || ns_bvci == 1) {
Harald Weltee5209642020-12-05 19:59:45 +0100399 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not PTP\n", log_pfx, ns_bvci);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100400 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100401 }
402
403 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
Harald Weltee5209642020-12-05 19:59:45 +0100404 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100405 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100406 }
407
408 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_UL)) {
Harald Weltee5209642020-12-05 19:59:45 +0100409 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100410 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100411 }
412
Harald Weltee5209642020-12-05 19:59:45 +0100413 bss_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);
414 if (!bss_bvc) {
415 LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for PTP message, discarding\n",
416 log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100417 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200418 }
419
Harald Weltee5209642020-12-05 19:59:45 +0100420 /* UL_UNITDATA has a different header than all other uplink PDUs */
421 if (bgph->pdu_type == BSSGP_PDUT_UL_UNITDATA) {
422 const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
423 if (msgb_bssgp_len(msg) < sizeof(*budh))
Daniel Willmannf8cba652021-02-12 04:59:47 +0100424 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Harald Weltee5209642020-12-05 19:59:45 +0100425 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, budh->data,
426 msgb_bssgp_len(msg) - sizeof(*budh), 0, 0, DGPRS, log_pfx);
427 /* populate TLLI from the fixed headser into the TLV-parsed array so later code
428 * doesn't have to worry where the TLLI came from */
429 tp.lv[BSSGP_IE_TLLI].len = 4;
430 tp.lv[BSSGP_IE_TLLI].val = (const uint8_t *) &budh->tlli;
431 } else {
432 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, bgph->data,
433 msgb_bssgp_len(msg) - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
434 }
435 if (rc < 0) {
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200436 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_BSS));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100437 return tx_status_from_tlvp(nse, rc, msg);
Harald Weltee5209642020-12-05 19:59:45 +0100438 }
Harald Welte85a40272020-12-08 21:43:22 +0100439 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
440 msgb_bcid(msg) = (void *)&tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200441
Harald Weltee5209642020-12-05 19:59:45 +0100442 switch (bgph->pdu_type) {
443 case BSSGP_PDUT_UL_UNITDATA:
444 case BSSGP_PDUT_RA_CAPA_UPDATE:
445 case BSSGP_PDUT_FLOW_CONTROL_MS:
446 case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
447 case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
448 case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
449 case BSSGP_PDUT_MODIFY_BSS_PFC_ACK:
450 case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
451 case BSSGP_PDUT_FLOW_CONTROL_PFC:
452 case BSSGP_PDUT_DELETE_BSS_PFC_REQ:
453 case BSSGP_PDUT_PS_HO_REQUIRED:
454 case BSSGP_PDUT_PS_HO_REQUEST_ACK:
455 case BSSGP_PDUT_PS_HO_REQUEST_NACK:
456 case BSSGP_PDUT_PS_HO_COMPLETE:
457 case BSSGP_PDUT_PS_HO_CANCEL:
458 /* We can route based on TLLI-NRI */
459 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100460 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, &tlli, false);
Harald Weltee5209642020-12-05 19:59:45 +0100461 break;
462 case BSSGP_PDUT_RADIO_STATUS:
463 if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
464 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100465 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, &tlli, false);
Harald Weltee5209642020-12-05 19:59:45 +0100466 } else if (TLVP_PRESENT(&tp, BSSGP_IE_TMSI)) {
467 /* we treat the TMSI like a TLLI and extract the NRI from it */
468 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TMSI));
Daniel Willmann8b3ed292021-01-21 18:46:51 +0100469 /* Convert the TMSI into a FOREIGN TLLI so it is routed appropriately */
470 tlli = gprs_tmsi2tlli(tlli, TLLI_FOREIGN);
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 } else if (TLVP_PRESENT(&tp, BSSGP_IE_IMSI)) {
Daniel Willmann5193f222021-01-11 05:00:46 +0100473 /* FIXME: Use the IMSI as selector? */
Daniel Willmannd4ab1f92020-12-21 18:53:55 +0100474 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, NULL, false);
Harald Weltee5209642020-12-05 19:59:45 +0100475 } else
476 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx RADIO-STATUS without any of the conditional IEs\n");
477 break;
478 case BSSGP_PDUT_DUMMY_PAGING_PS_RESP:
479 case BSSGP_PDUT_PAGING_PS_REJECT:
Daniel Willmann5614e572021-01-18 18:38:27 +0100480 {
481 /* Route according to IMSI<->NSE cache entry */
482 struct osmo_mobile_identity mi;
483 const uint8_t *mi_data = TLVP_VAL(&tp, BSSGP_IE_IMSI);
484 uint8_t mi_len = TLVP_LEN(&tp, BSSGP_IE_IMSI);
485 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +0200486 nse = gbproxy_nse_by_imsi(nse->cfg, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann5614e572021-01-18 18:38:27 +0100487 if (nse) {
488 OSMO_ASSERT(nse->sgsn_facing);
489 rc = gbprox_relay2nse(msg, nse, ns_bvci);
490 } else {
Daniel Willmann82669182021-01-19 11:37:55 +0100491 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx unmatched %s with IMSI %s\n", pdut_name, mi.imsi);
Daniel Willmann5614e572021-01-18 18:38:27 +0100492 }
Harald Weltee5209642020-12-05 19:59:45 +0100493 break;
Daniel Willmann5614e572021-01-18 18:38:27 +0100494 }
Harald Weltee5209642020-12-05 19:59:45 +0100495 case BSSGP_PDUT_FLOW_CONTROL_BVC:
Harald Welte85a40272020-12-08 21:43:22 +0100496 osmo_fsm_inst_dispatch(bss_bvc->fi, BSSGP_BVCFSM_E_RX_FC_BVC, msg);
Harald Weltee5209642020-12-05 19:59:45 +0100497 break;
498 case BSSGP_PDUT_STATUS:
499 /* TODO: Implement by inspecting the contained PDU */
500 if (!TLVP_PRESENT(&tp, BSSGP_IE_PDU_IN_ERROR))
501 break;
502 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);
503 break;
504 }
505
506 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200507}
508
509/* Receive an incoming PTP message from a SGSN-side NS-VC */
Harald Weltee5209642020-12-05 19:59:45 +0100510static 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 +0200511{
Harald Welte278dd272020-12-06 13:35:24 +0100512 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Weltee5209642020-12-05 19:59:45 +0100513 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
514 struct gbproxy_bvc *sgsn_bvc, *bss_bvc;
Harald Welte85a40272020-12-08 21:43:22 +0100515 struct tlv_parsed tp;
Harald Weltee5209642020-12-05 19:59:45 +0100516 char log_pfx[32];
Harald Welte85a40272020-12-08 21:43:22 +0100517 int rc;
Harald Weltee5209642020-12-05 19:59:45 +0100518
519 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);
520
521 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200522
Daniel Willmann06331ac2020-12-10 17:59:46 +0100523 if (ns_bvci == 0 || ns_bvci == 1) {
Harald Weltee5209642020-12-05 19:59:45 +0100524 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI is not PTP\n", log_pfx);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100525 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100526 }
527
528 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
Harald Weltee5209642020-12-05 19:59:45 +0100529 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100530 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100531 }
532
533 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_DL)) {
Harald Weltee5209642020-12-05 19:59:45 +0100534 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100535 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +0100536 }
537
Harald Weltee5209642020-12-05 19:59:45 +0100538 sgsn_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);
539 if (!sgsn_bvc) {
540 LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for for PTP message, discarding\n",
541 log_pfx, pdut_name);
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200542 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100543 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200544 }
545
Harald Weltee5209642020-12-05 19:59:45 +0100546 if (!bssgp_bvc_fsm_is_unblocked(sgsn_bvc->fi)) {
547 LOGPBVC(sgsn_bvc, LOGL_NOTICE, "Rx %s: Dropping on blocked BVC\n", pdut_name);
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200548 rate_ctr_inc(rate_ctr_group_get_ctr(sgsn_bvc->ctrg, GBPROX_PEER_CTR_DROPPED));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100549 return tx_status(nse, ns_bvci, BSSGP_CAUSE_BVCI_BLOCKED, &ns_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200550 }
Harald Welte85a40272020-12-08 21:43:22 +0100551
552 /* DL_UNITDATA has a different header than all other uplink PDUs */
553 if (bgph->pdu_type == BSSGP_PDUT_DL_UNITDATA) {
554 const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
555 if (msgb_bssgp_len(msg) < sizeof(*budh))
Daniel Willmannf8cba652021-02-12 04:59:47 +0100556 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Harald Welte85a40272020-12-08 21:43:22 +0100557 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, budh->data,
558 msgb_bssgp_len(msg) - sizeof(*budh), 0, 0, DGPRS, log_pfx);
559 /* populate TLLI from the fixed headser into the TLV-parsed array so later code
560 * doesn't have to worry where the TLLI came from */
561 tp.lv[BSSGP_IE_TLLI].len = 4;
562 tp.lv[BSSGP_IE_TLLI].val = (const uint8_t *) &budh->tlli;
563 } else {
564 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, bgph->data,
565 msgb_bssgp_len(msg) - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
566 }
567 if (rc < 0) {
Pau Espin Pedrol56438362021-06-04 18:03:44 +0200568 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_BSS));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100569 return tx_status_from_tlvp(nse, rc, msg);
Harald Welte85a40272020-12-08 21:43:22 +0100570 }
571 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
572 msgb_bcid(msg) = (void *)&tp;
573
Harald Weltee5209642020-12-05 19:59:45 +0100574 OSMO_ASSERT(sgsn_bvc->cell);
575 bss_bvc = sgsn_bvc->cell->bss_bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200576
Harald Welte85a40272020-12-08 21:43:22 +0100577 switch (bgph->pdu_type) {
578 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
579 return osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_FC_BVC_ACK, msg);
Daniel Willmann5614e572021-01-18 18:38:27 +0100580 case BSSGP_PDUT_DUMMY_PAGING_PS:
581 case BSSGP_PDUT_PAGING_PS:
582 {
583 /* Cache the IMSI<->NSE to route PAGING REJECT */
584 struct osmo_mobile_identity mi;
585 const uint8_t *mi_data = TLVP_VAL(&tp, BSSGP_IE_IMSI);
586 uint8_t mi_len = TLVP_LEN(&tp, BSSGP_IE_IMSI);
587 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +0200588 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann5614e572021-01-18 18:38:27 +0100589 break;
Harald Welte85a40272020-12-08 21:43:22 +0100590 }
Daniel Willmann5614e572021-01-18 18:38:27 +0100591 default:
592 break;
593 }
594 return gbprox_relay2peer(msg, bss_bvc, bss_bvc->bvci);
Harald Welte85a40272020-12-08 21:43:22 +0100595
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200596}
597
Harald Weltee5209642020-12-05 19:59:45 +0100598/***********************************************************************
599 * BVC FSM call-backs
600 ***********************************************************************/
Harald Welte7df1e5a2020-12-02 22:53:26 +0100601
Harald Weltee5209642020-12-05 19:59:45 +0100602/* helper function to dispatch a FSM event to all SGSN-side BVC FSMs of a cell */
603static void dispatch_to_all_sgsn_bvc(struct gbproxy_cell *cell, uint32_t event, void *priv)
604{
605 unsigned int i;
606
607 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
608 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[i];
609 if (!sgsn_bvc)
610 continue;
611 osmo_fsm_inst_dispatch(sgsn_bvc->fi, event, priv);
612 }
613}
614
615/* BVC FSM informs us about a BSS-side reset of the signaling BVC */
616static void bss_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
617 uint16_t cell_id, uint8_t cause, void *priv)
618{
619 struct gbproxy_bvc *sig_bvc = priv;
620 struct gbproxy_nse *nse = sig_bvc->nse;
621 struct gbproxy_bvc *ptp_bvc;
622 unsigned int i;
623
624 /* BLOCK all SGSN-side PTP BVC within this NSE */
625 hash_for_each(nse->bvcs, i, ptp_bvc, list) {
626 if (ptp_bvc == sig_bvc)
627 continue;
628 OSMO_ASSERT(ptp_bvc->cell);
629
630 dispatch_to_all_sgsn_bvc(ptp_bvc->cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
Harald Weltef9e149b2020-12-02 23:29:38 +0100631 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100632
Harald Weltee5209642020-12-05 19:59:45 +0100633 /* Delete all BSS-side PTP BVC within this NSE */
634 gbproxy_cleanup_bvcs(nse, 0);
635
636 /* TODO: we keep the "CELL" around for now, re-connecting it to
637 * any (later) new PTP-BVC for that BVCI. Not sure if that's the
638 * best idea ? */
639}
640
641/* forward declaration */
642static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops;
643
644static const struct bssgp_bvc_fsm_ops bss_sig_bvc_fsm_ops = {
645 .reset_notification = bss_sig_bvc_reset_notif,
646};
647
648/* BVC FSM informs us about a BSS-side reset of a PTP BVC */
649static void bss_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
650 uint16_t cell_id, uint8_t cause, void *priv)
651{
652 struct gbproxy_bvc *bvc = priv;
653 struct gbproxy_config *cfg = bvc->nse->cfg;
Harald Welte664c24e2020-12-12 15:01:17 +0100654 struct gbproxy_nse *sgsn_nse;
Harald Weltee5209642020-12-05 19:59:45 +0100655 unsigned int i;
656
657 OSMO_ASSERT(bvci != 0);
658
659 if (!bvc->cell) {
660 /* see if we have a CELL dangling around */
661 bvc->cell = gbproxy_cell_by_bvci(cfg, bvci);
662 if (bvc->cell) {
663 /* the CELL already exists. This means either it * was created before at an
664 * earlier PTP BVC-RESET, or that there are non-unique BVCIs and hence a
665 * malconfiguration */
666 if (bvc->cell->bss_bvc) {
667 LOGPBVC(bvc, LOGL_NOTICE, "Rx BVC-RESET via this NSE, but CELL already "
668 "has BVC on NSEI=%05u\n", bvc->cell->bss_bvc->nse->nsei);
669 LOGPBVC(bvc->cell->bss_bvc, LOGL_NOTICE, "Destroying due to conflicting "
670 "BVCI configuration (new NSEI=%05u)!\n", bvc->nse->nsei);
671 gbproxy_bvc_free(bvc->cell->bss_bvc);
672 }
673 bvc->cell->bss_bvc = bvc;
674 }
675 }
676
677 if (!bvc->cell) {
Harald Weltee5209642020-12-05 19:59:45 +0100678 /* if we end up here, it means this is the first time we received a BVC-RESET
679 * for this BVC. We need to create the 'cell' data structure and the SGSN-side
680 * BVC counterparts */
681
Philipp Maiere4597ec2021-02-09 16:02:00 +0100682 bvc->cell = gbproxy_cell_alloc(cfg, bvci, ra_id, cell_id);
Harald Weltee5209642020-12-05 19:59:45 +0100683 OSMO_ASSERT(bvc->cell);
684
685 /* link us to the cell and vice-versa */
686 bvc->cell->bss_bvc = bvc;
Harald Welte664c24e2020-12-12 15:01:17 +0100687 }
Harald Weltee5209642020-12-05 19:59:45 +0100688
Daniel Willmann6701d272021-04-08 08:39:12 +0200689 /* Ensure we have the correct RA/CELL ID */
690 if (!gsm48_ra_equal(&bvc->cell->id.raid, ra_id)) {
691 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));
692 memcpy(&bvc->cell->id.raid, ra_id, sizeof(*ra_id));
693 }
694 if (bvc->cell->id.cid != cell_id) {
695 LOGPBVC(bvc, LOGL_NOTICE, "CellID changed from %05d to %05d, updating cell\n", bvc->cell->id.cid, cell_id);
696 bvc->cell->id.cid = cell_id;
697 }
698
699 /* Reallocate SGSN-side BVCs of the cell, and reset them
700 * Removing and reallocating is needed becaus the ra_id/cell_id might have changed */
Harald Welte664c24e2020-12-12 15:01:17 +0100701 hash_for_each(cfg->sgsn_nses, i, sgsn_nse, list) {
702 struct gbproxy_bvc *sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
Daniel Willmanndc763fd2021-09-24 16:45:38 +0200703 if (!sgsn_bvc)
704 sgsn_bvc = gbproxy_bvc_by_bvci_inactive(sgsn_nse, bvci);
Harald Welte664c24e2020-12-12 15:01:17 +0100705 if (sgsn_bvc)
Daniel Willmann6701d272021-04-08 08:39:12 +0200706 gbproxy_bvc_free(sgsn_bvc);
Harald Weltee5209642020-12-05 19:59:45 +0100707
Daniel Willmann6701d272021-04-08 08:39:12 +0200708 sgsn_bvc = gbproxy_bvc_alloc(sgsn_nse, bvci);
709 OSMO_ASSERT(sgsn_bvc);
710 sgsn_bvc->cell = bvc->cell;
711 memcpy(&sgsn_bvc->raid, &bvc->cell->id.raid, sizeof(sgsn_bvc->raid));
712 sgsn_bvc->fi = bssgp_bvc_fsm_alloc_ptp_bss(sgsn_bvc, cfg->nsi, sgsn_nse->nsei,
713 bvci, ra_id, cell_id);
714 OSMO_ASSERT(sgsn_bvc->fi);
715 bssgp_bvc_fsm_set_max_pdu_len(sgsn_bvc->fi, sgsn_nse->max_sdu_len);
716 bssgp_bvc_fsm_set_ops(sgsn_bvc->fi, &sgsn_ptp_bvc_fsm_ops, sgsn_bvc);
717 gbproxy_cell_add_sgsn_bvc(bvc->cell, sgsn_bvc);
Harald Weltee5209642020-12-05 19:59:45 +0100718 }
719
720 /* Trigger outbound BVC-RESET procedure toward each SGSN */
721 dispatch_to_all_sgsn_bvc(bvc->cell, BSSGP_BVCFSM_E_REQ_RESET, &cause);
722}
723
724/* BVC FSM informs us about a BSS-side FSM state change */
725static void bss_ptp_bvc_state_chg_notif(uint16_t nsei, uint16_t bvci, int old_state, int state, void *priv)
726{
727 struct gbproxy_bvc *bvc = priv;
728 struct gbproxy_cell *cell = bvc->cell;
729 uint8_t cause = bssgp_bvc_fsm_get_block_cause(bvc->fi);
730
731 /* we have just been created but due to callback ordering the cell is not associated */
732 if (!cell)
733 return;
734
735 switch (state) {
736 case BSSGP_BVCFSM_S_BLOCKED:
737 /* block the corresponding SGSN-side PTP BVCs */
738 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
739 break;
740 case BSSGP_BVCFSM_S_UNBLOCKED:
741 /* unblock the corresponding SGSN-side PTP BVCs */
742 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_UNBLOCK, NULL);
743 break;
744 }
745}
746
Harald Welte85a40272020-12-08 21:43:22 +0100747/* BVC FSM informs us about BVC-FC PDU receive */
748static void bss_ptp_bvc_fc_bvc(uint16_t nsei, uint16_t bvci, const struct bssgp2_flow_ctrl *fc, void *priv)
749{
Harald Welte209dc9f2020-12-12 19:02:16 +0100750 struct bssgp2_flow_ctrl fc_reduced;
Harald Welte85a40272020-12-08 21:43:22 +0100751 struct gbproxy_bvc *bss_bvc = priv;
Harald Welte209dc9f2020-12-12 19:02:16 +0100752 struct gbproxy_cell *cell;
753 struct gbproxy_config *cfg;
Harald Welte85a40272020-12-08 21:43:22 +0100754
Harald Welte209dc9f2020-12-12 19:02:16 +0100755 OSMO_ASSERT(bss_bvc);
756 OSMO_ASSERT(fc);
757
758 cell = bss_bvc->cell;
Harald Welte85a40272020-12-08 21:43:22 +0100759 if (!cell)
760 return;
761
Harald Welte209dc9f2020-12-12 19:02:16 +0100762 cfg = cell->cfg;
Harald Welte85a40272020-12-08 21:43:22 +0100763
Harald Welte209dc9f2020-12-12 19:02:16 +0100764 /* reduce / scale according to configuration to make sure we only advertise a fraction
765 * of the capacity to each of the SGSNs in the pool */
766 fc_reduced = *fc;
767 fc_reduced.bucket_size_max = (fc->bucket_size_max * cfg->pool.bvc_fc_ratio) / 100;
768 fc_reduced.bucket_leak_rate = (fc->bucket_leak_rate * cfg->pool.bvc_fc_ratio) / 100;
769 /* we don't modify the per-MS related values as any single MS is only served by one SGSN */
770
771 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_FC_BVC, (void *) &fc_reduced);
Harald Welte85a40272020-12-08 21:43:22 +0100772}
773
Harald Weltee5209642020-12-05 19:59:45 +0100774static const struct bssgp_bvc_fsm_ops bss_ptp_bvc_fsm_ops = {
775 .reset_notification = bss_ptp_bvc_reset_notif,
776 .state_chg_notification = bss_ptp_bvc_state_chg_notif,
Harald Welte85a40272020-12-08 21:43:22 +0100777 .rx_fc_bvc = bss_ptp_bvc_fc_bvc,
Harald Weltee5209642020-12-05 19:59:45 +0100778};
779
780/* BVC FSM informs us about a SGSN-side reset of a PTP BVC */
781static void sgsn_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
782 uint16_t cell_id, uint8_t cause, void *priv)
783{
784 struct gbproxy_bvc *bvc = priv;
785
786 if (!bvc->cell) {
787 LOGPBVC(bvc, LOGL_ERROR, "RESET of PTP BVC on SGSN side for which we have no BSS?\n");
788 return;
789 }
790
791 OSMO_ASSERT(bvc->cell->bss_bvc);
792
793 /* request reset of BSS-facing PTP-BVC */
794 osmo_fsm_inst_dispatch(bvc->cell->bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
795}
796
797static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops = {
798 .reset_notification = sgsn_ptp_bvc_reset_notif,
799};
800
801/* BVC FSM informs us about a SGSN-side reset of the signaling BVC */
802static void sgsn_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
803 uint16_t cell_id, uint8_t cause, void *priv)
804{
805 struct gbproxy_bvc *bvc = priv;
806 struct gbproxy_config *cfg = bvc->nse->cfg;
807 struct gbproxy_nse *bss_nse;
808 unsigned int i;
809
810 /* delete all SGSN-side PTP BVC for this SGSN */
811 gbproxy_cleanup_bvcs(bvc->nse, 0);
812 /* FIXME: what to do about the cells? */
813 /* FIXME: do we really want to RESET all signaling BVC on the BSS and affect all other SGSN? */
814
815 /* we need to trigger generating a reset procedure towards each BSS side signaling BVC */
816 hash_for_each(cfg->bss_nses, i, bss_nse, list) {
817 struct gbproxy_bvc *bss_bvc = gbproxy_bvc_by_bvci(bss_nse, 0);
818 if (!bss_bvc) {
819 LOGPNSE(bss_nse, LOGL_ERROR, "Doesn't have BVC with BVCI=0 ?!?\n");
820 continue;
821 }
822 osmo_fsm_inst_dispatch(bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
823 }
824}
825
826const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops = {
827 .reset_notification = sgsn_sig_bvc_reset_notif,
828};
829
830/***********************************************************************
831 * Signaling BVC handling
832 ***********************************************************************/
833
834/* process a BVC-RESET message from the BSS side */
835static int rx_bvc_reset_from_bss(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp)
836{
837 struct gbproxy_bvc *from_bvc = NULL;
838 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
839 uint32_t features = 0; // FIXME: make configurable
840
841 LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", bvci);
842
Harald Welte314647b2020-12-02 23:03:22 +0100843 if (bvci == 0) {
844 /* If we receive a BVC reset on the signalling endpoint, we
845 * don't want the SGSN to reset, as the signalling endpoint
846 * is common for all point-to-point BVCs (and thus all BTS) */
Harald Welte324f0652020-12-02 23:06:37 +0100847
Harald Weltee5209642020-12-05 19:59:45 +0100848 from_bvc = gbproxy_bvc_by_bvci(nse, 0);
Harald Welte560bdb32020-12-04 22:24:47 +0100849 if (!from_bvc) {
Harald Weltee5209642020-12-05 19:59:45 +0100850 from_bvc = gbproxy_bvc_alloc(nse, 0);
851 OSMO_ASSERT(from_bvc);
852 from_bvc->fi = bssgp_bvc_fsm_alloc_sig_sgsn(from_bvc, nse->cfg->nsi, nse->nsei, features);
853 if (!from_bvc->fi) {
854 LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");
855 gbproxy_bvc_free(from_bvc);
856 return -ENOMEM;
Harald Welte7df1e5a2020-12-02 22:53:26 +0100857 }
Daniel Willmanna8b61652021-02-12 05:05:14 +0100858 bssgp_bvc_fsm_set_max_pdu_len(from_bvc->fi, nse->max_sdu_len);
Harald Weltee5209642020-12-05 19:59:45 +0100859 bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_sig_bvc_fsm_ops, from_bvc);
860 }
861 } else {
862 from_bvc = gbproxy_bvc_by_bvci(nse, bvci);
863 if (!from_bvc) {
Harald Welte7df1e5a2020-12-02 22:53:26 +0100864 /* if a PTP-BVC is reset, and we don't know that
Harald Welte560bdb32020-12-04 22:24:47 +0100865 * PTP-BVCI yet, we should allocate a new bvc */
866 from_bvc = gbproxy_bvc_alloc(nse, bvci);
867 OSMO_ASSERT(from_bvc);
Harald Weltee5209642020-12-05 19:59:45 +0100868 from_bvc->fi = bssgp_bvc_fsm_alloc_ptp_sgsn(from_bvc, nse->cfg->nsi,
869 nse->nsei, bvci);
870 if (!from_bvc->fi) {
871 LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");
872 gbproxy_bvc_free(from_bvc);
873 return -ENOMEM;
874 }
Daniel Willmanna8b61652021-02-12 05:05:14 +0100875 bssgp_bvc_fsm_set_max_pdu_len(from_bvc->fi, nse->max_sdu_len);
Harald Weltee5209642020-12-05 19:59:45 +0100876 bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_ptp_bvc_fsm_ops, from_bvc);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100877 }
Harald Weltee5209642020-12-05 19:59:45 +0100878#if 0
Harald Welte7df1e5a2020-12-02 22:53:26 +0100879 /* Could have moved to a different NSE */
Harald Welte560bdb32020-12-04 22:24:47 +0100880 if (!check_bvc_nsei(from_bvc, nsei)) {
881 LOGPBVC(from_bvc, LOGL_NOTICE, "moving bvc to NSE(%05u)\n", nsei);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100882
Harald Weltee5209642020-12-05 19:59:45 +0100883 struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei(cfg, nsei, false);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100884 if (!nse_new) {
885 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "
886 "BVCI=%05u\n", bvci, nsei);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100887 tx_status(nse, ns_bvci, BSSGP_CAUSE_PDU_INCOMP_STATE, NULL, msg);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100888 return 0;
889 }
890
Harald Welte560bdb32020-12-04 22:24:47 +0100891 /* Move bvc to different NSE */
892 gbproxy_bvc_move(from_bvc, nse_new);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100893 }
Harald Weltee5209642020-12-05 19:59:45 +0100894#endif
895 /* FIXME: do we need this, if it happens within FSM? */
Harald Welte173a1822020-12-03 15:36:59 +0100896 if (TLVP_PRES_LEN(tp, BSSGP_IE_CELL_ID, 8)) {
Harald Welte7df1e5a2020-12-02 22:53:26 +0100897 struct gprs_ra_id raid;
898 /* We have a Cell Identifier present in this
899 * PDU, this means we can extend our local
900 * state information about this particular cell
901 * */
Philipp Maierda3af942021-02-04 21:54:09 +0100902 gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_CELL_ID));
903 memcpy(&from_bvc->raid, &raid, sizeof(from_bvc->raid));
Harald Welte560bdb32020-12-04 22:24:47 +0100904 LOGPBVC(from_bvc, LOGL_INFO, "Cell ID %s\n", osmo_rai_name(&raid));
Harald Welte7df1e5a2020-12-02 22:53:26 +0100905 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100906 }
Harald Weltee5209642020-12-05 19:59:45 +0100907 /* hand into FSM for further processing */
908 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
909 return 0;
Harald Welte7df1e5a2020-12-02 22:53:26 +0100910}
911
Philipp Maier1c5766b2021-02-09 17:03:03 +0100912/* Receive an incoming RIM message from a BSS-side NS-VC */
913static int gbprox_rx_rim_from_bss(struct tlv_parsed *tp, struct gbproxy_nse *nse, struct msgb *msg, char *log_pfx,
914 const char *pdut_name)
915{
916 struct gbproxy_sgsn *sgsn;
917 struct gbproxy_cell *dest_cell;
918 struct gbproxy_cell *src_cell;
919 struct bssgp_rim_routing_info dest_ri;
920 struct bssgp_rim_routing_info src_ri;
921 int rc;
Philipp Maier4499cf42021-02-10 17:54:44 +0100922 char ri_src_str[64];
923 char ri_dest_str[64];
Daniel Willmannf8cba652021-02-12 04:59:47 +0100924 uint16_t ns_bvci = msgb_bvci(msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100925
926 rc = bssgp_parse_rim_ri(&dest_ri, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
927 TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
928 if (rc < 0) {
929 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse destination RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100930 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100931 }
932 rc = bssgp_parse_rim_ri(&src_ri, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
933 TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
934 if (rc < 0) {
935 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse source RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +0100936 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100937 }
938
939 /* Since gbproxy is 2G only we do not expect to get RIM messages only from GERAN cells. */
940 if (src_ri.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
941 LOGP(DGPRS, LOGL_ERROR, "%s %s source RIM routing info is not GERAN (%s)\n", log_pfx, pdut_name,
942 bssgp_rim_ri_name(&src_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100943 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100944 }
945
946 /* Lookup source cell to make sure that the source RIM routing information actually belongs
947 * to a valid cell that we know */
948 src_cell = gbproxy_cell_by_cellid(nse->cfg, &src_ri.geran.raid, src_ri.geran.cid);
949 if (!src_cell) {
950 LOGP(DGPRS, LOGL_NOTICE, "%s %s cannot find cell for source RIM routing info (%s)\n", log_pfx,
951 pdut_name, bssgp_rim_ri_name(&src_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100952 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100953 }
954
955 /* TODO: Use bssgp_bvc_get_features_negotiated(src_cell->bss_bvc->fi) to check if the the BSS sided BVC actually
956 * did negotiate RIM support. If not we should respond with a BSSGP STATUS message. The cause code should be
957 * BSSGP_CAUSE_PDU_INCOMP_FEAT. */
958
959 /* If Destination is known by gbproxy, route directly */
960 if (dest_ri.discr == BSSGP_RIM_ROUTING_INFO_GERAN) {
961 dest_cell = gbproxy_cell_by_cellid(nse->cfg, &dest_ri.geran.raid, dest_ri.geran.cid);
962 if (dest_cell) {
963 /* TODO: Also check if dest_cell->bss_bvc is RIM-capable (see also above). If not we should
964 * respond with a BSSGP STATUS message as well because it also would make no sense to try
965 * routing the RIM message to the next RIM-capable SGSN. */
Philipp Maier4499cf42021-02-10 17:54:44 +0100966 LOGP(DLBSSGP, LOGL_DEBUG, "%s %s relaying to peer (nsei=%u) RIM-PDU: src=%s, dest=%s\n",
967 log_pfx, pdut_name, dest_cell->bss_bvc->nse->nsei,
968 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &src_ri),
969 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &dest_ri));
Philipp Maier1c5766b2021-02-09 17:03:03 +0100970 return gbprox_relay2peer(msg, dest_cell->bss_bvc, 0);
971 }
972 }
973
974 /* Otherwise pass on to a RIM-capable SGSN */
975 /* TODO: We need to extend gbproxy_select_sgsn() so that it selects a RIM-capable SGSN, at the moment we just
976 * get any SGSN and just assume that it is RIM-capable. */
977 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
978 if (!sgsn) {
979 LOGP(DGPRS, LOGL_NOTICE,
980 "%s %s cannot route RIM message (%s to %s) since no RIM capable SGSN is found!\n", log_pfx,
981 pdut_name, bssgp_rim_ri_name(&src_ri), bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +0100982 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +0100983 }
Philipp Maier4499cf42021-02-10 17:54:44 +0100984 LOGP(DLBSSGP, LOGL_DEBUG, "%s %s relaying to SGSN(%05u/%s) RIM-PDU: src=%s, dest=%s\n",
985 log_pfx, pdut_name, sgsn->nse->nsei, sgsn->name,
986 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &src_ri),
987 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &dest_ri));
Philipp Maier1c5766b2021-02-09 17:03:03 +0100988
989 return gbprox_relay2nse(msg, sgsn->nse, 0);
990}
991
Daniel Willmann6ec5f952021-10-28 16:13:03 +0200992/* Extract the TLLI from the PDU-in-error of the STATUS PDU (if available) */
993static int gbproxy_tlli_from_status_pdu(struct tlv_parsed *tp, uint32_t *tlli, char *log_pfx)
Daniel Willmann7d37cbb2021-09-29 11:51:51 +0200994{
995 int rc;
996 int pdu_len = TLVP_LEN(&tp[0], BSSGP_IE_PDU_IN_ERROR);
997 const uint8_t *pdu_data = TLVP_VAL(&tp[0], BSSGP_IE_PDU_IN_ERROR);
998 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)pdu_data;
999 struct tlv_parsed tp_inner[2];
1000
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001001 /* TODO: Parse partial messages as well */
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001002 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp_inner, ARRAY_SIZE(tp_inner), bgph->pdu_type, bgph->data,
1003 pdu_len - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
1004
1005 if (rc < 0)
1006 return rc;
1007
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +02001008 if (TLVP_PRESENT(&tp_inner[0], BSSGP_IE_TLLI)) {
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001009 *tlli = osmo_load32be(TLVP_VAL(&tp_inner[0], BSSGP_IE_TLLI));
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +02001010 } else if (TLVP_PRESENT(&tp_inner[0], BSSGP_IE_TMSI)) {
1011 /* we treat the TMSI like a TLLI and extract the NRI from it */
1012 *tlli = osmo_load32be(TLVP_VAL(&tp_inner[0], BSSGP_IE_TMSI));
1013 /* Convert the TMSI into a FOREIGN TLLI so it is routed appropriately */
1014 *tlli = gprs_tmsi2tlli(*tlli, TLLI_FOREIGN);
1015 } else {
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001016 return -ENOENT;
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +02001017 }
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001018
1019 return 0;
1020}
1021
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001022/* Extract the BVCI from the PDU-in-error of the STATUS PDU (if available) */
1023static int gbproxy_bvci_from_status_pdu(struct tlv_parsed *tp, uint16_t *bvci, char *log_pfx)
1024{
1025 int rc;
1026 int pdu_len = TLVP_LEN(&tp[0], BSSGP_IE_PDU_IN_ERROR);
1027 const uint8_t *pdu_data = TLVP_VAL(&tp[0], BSSGP_IE_PDU_IN_ERROR);
1028 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)pdu_data;
1029 struct tlv_parsed tp_inner[2];
1030
1031 /* TODO: Parse partial messages as well */
1032 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp_inner, ARRAY_SIZE(tp_inner), bgph->pdu_type, bgph->data,
1033 pdu_len - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
1034
1035 if (rc < 0)
1036 return rc;
1037
1038 if (TLVP_PRESENT(&tp_inner[0], BSSGP_IE_BVCI))
1039 *bvci = ntohs(tlvp_val16_unal(&tp_inner[0], BSSGP_IE_BVCI));
1040 else
1041 return -ENOENT;
1042
1043 return 0;
1044}
1045
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001046/* Receive an incoming signalling message from a BSS-side NS-VC */
Harald Weltee5209642020-12-05 19:59:45 +01001047static 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 +02001048{
1049 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001050 uint8_t pdu_type = bgph->pdu_type;
Harald Weltee5209642020-12-05 19:59:45 +01001051 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
Philipp Maier74882dc2021-02-04 16:31:46 +01001052 struct tlv_parsed tp[2];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001053 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welte560bdb32020-12-04 22:24:47 +01001054 struct gbproxy_bvc *from_bvc = NULL;
Harald Welteec0f8012020-12-06 16:32:01 +01001055 char log_pfx[32];
Harald Weltee5209642020-12-05 19:59:45 +01001056 uint16_t ptp_bvci;
1057 uint32_t tlli;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001058 int rc;
1059
Harald Weltee5209642020-12-05 19:59:45 +01001060 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);
1061
1062 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welteec0f8012020-12-06 16:32:01 +01001063
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001064 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Weltee5209642020-12-05 19:59:45 +01001065 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 +01001066 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001067 }
1068
Harald Welte278dd272020-12-06 13:35:24 +01001069 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Weltee5209642020-12-05 19:59:45 +01001070 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001071 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +01001072 }
1073
1074 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_UL)) {
Harald Weltee5209642020-12-05 19:59:45 +01001075 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001076 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001077 }
1078
Philipp Maier74882dc2021-02-04 16:31:46 +01001079 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 +01001080 DGPRS, log_pfx);
1081 if (rc < 0) {
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001082 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_BSS));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001083 return tx_status_from_tlvp(nse, rc, msg);
Harald Welteec0f8012020-12-06 16:32:01 +01001084 }
Harald Weltee5209642020-12-05 19:59:45 +01001085 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
Philipp Maier74882dc2021-02-04 16:31:46 +01001086 msgb_bcid(msg) = (void *)tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001087
Harald Weltee5209642020-12-05 19:59:45 +01001088 /* special case handling for some PDU types */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001089 switch (pdu_type) {
Harald Weltee5209642020-12-05 19:59:45 +01001090 case BSSGP_PDUT_BVC_RESET:
1091 /* resolve or create gbproxy_bvc + handlei n BVC-FSM */
Philipp Maier74882dc2021-02-04 16:31:46 +01001092 return rx_bvc_reset_from_bss(nse, msg, &tp[0]);
Harald Weltee5209642020-12-05 19:59:45 +01001093 case BSSGP_PDUT_BVC_RESET_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001094 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001095 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
Harald Welte560bdb32020-12-04 22:24:47 +01001096 if (!from_bvc)
1097 goto err_no_bvc;
Harald Weltee5209642020-12-05 19:59:45 +01001098 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
1099 case BSSGP_PDUT_BVC_BLOCK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001100 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001101 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1102 if (!from_bvc)
1103 goto err_no_bvc;
1104 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK, msg);
1105 case BSSGP_PDUT_BVC_UNBLOCK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001106 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001107 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1108 if (!from_bvc)
1109 goto err_no_bvc;
1110 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK, msg);
1111 case BSSGP_PDUT_SUSPEND:
1112 case BSSGP_PDUT_RESUME:
Daniel Willmann77493b12020-12-29 21:13:31 +01001113 {
1114 struct gbproxy_sgsn *sgsn;
1115
Philipp Maier74882dc2021-02-04 16:31:46 +01001116 tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Daniel Willmann77493b12020-12-29 21:13:31 +01001117 sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
1118 if (!sgsn) {
1119 LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN for TLLI, dropping message!\n");
1120 rc = -EINVAL;
1121 break;
1122 }
1123
1124 gbproxy_tlli_cache_update(nse, tlli);
1125
1126 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
Harald Weltee5209642020-12-05 19:59:45 +01001127#if 0
1128 /* TODO: Validate the RAI for consistency with the RAI
1129 * we expect for any of the BVC within this BSS side NSE */
Philipp Maier74882dc2021-02-04 16:31:46 +01001130 memcpy(ra, TLVP_VAL(&tp[0], BSSGP_IE_ROUTEING_AREA), sizeof(from_bvc->ra));
Harald Welte560bdb32020-12-04 22:24:47 +01001131 gsm48_parse_ra(&raid, from_bvc->ra);
Harald Weltee5209642020-12-05 19:59:45 +01001132#endif
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001133 break;
Daniel Willmann77493b12020-12-29 21:13:31 +01001134 }
Harald Weltee5209642020-12-05 19:59:45 +01001135 case BSSGP_PDUT_STATUS:
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001136 {
1137 struct gbproxy_sgsn *sgsn;
1138 /* Check if the status needs to be terminated locally */
1139 uint8_t cause = *TLVP_VAL(&tp[0], BSSGP_IE_CAUSE);
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001140
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001141 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI || cause == BSSGP_CAUSE_BVCI_BLOCKED) {
1142 /* Log and handle locally */
1143 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001144 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s) for PtP-BVC %05u\n", cause,
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001145 bssgp_cause_str(cause), ptp_bvci);
1146 /* FIXME: Remove/block our BVC if present? */
1147 break;
1148 }
1149
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001150 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s) ", cause,
1151 bssgp_cause_str(cause));
1152
Daniel Willmann6ec5f952021-10-28 16:13:03 +02001153 if (gbproxy_tlli_from_status_pdu(tp, &tlli, log_pfx) == 0)
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001154 sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
1155 else
1156 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
1157
1158 if (!sgsn) {
1159 rc = -EINVAL;
1160 break;
1161 }
1162
1163 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
Harald Weltee5209642020-12-05 19:59:45 +01001164 break;
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001165 }
Harald Weltee5209642020-12-05 19:59:45 +01001166 case BSSGP_PDUT_RAN_INFO:
1167 case BSSGP_PDUT_RAN_INFO_REQ:
1168 case BSSGP_PDUT_RAN_INFO_ACK:
1169 case BSSGP_PDUT_RAN_INFO_ERROR:
1170 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
Philipp Maier1c5766b2021-02-09 17:03:03 +01001171 rc = gbprox_rx_rim_from_bss(tp, nse, msg, log_pfx, pdut_name);
Harald Weltee5209642020-12-05 19:59:45 +01001172 break;
1173 case BSSGP_PDUT_LLC_DISCARD:
1174 case BSSGP_PDUT_FLUSH_LL_ACK:
1175 /* route based on BVCI + TLLI */
Philipp Maier74882dc2021-02-04 16:31:46 +01001176 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1177 tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Harald Weltee5209642020-12-05 19:59:45 +01001178 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1179 if (!from_bvc)
1180 goto err_no_bvc;
Daniel Willmannd4ab1f92020-12-21 18:53:55 +01001181 gbprox_bss2sgsn_tlli(from_bvc->cell, msg, &tlli, true);
Harald Weltee5209642020-12-05 19:59:45 +01001182 break;
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001183 case BSSGP_PDUT_PAGING_PS_REJECT:
Daniel Willmann5614e572021-01-18 18:38:27 +01001184 case BSSGP_PDUT_DUMMY_PAGING_PS_RESP:
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001185 {
1186 /* Route according to IMSI<->NSE cache entry */
1187 struct osmo_mobile_identity mi;
Philipp Maier74882dc2021-02-04 16:31:46 +01001188 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1189 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001190 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +02001191 nse = gbproxy_nse_by_imsi(nse->cfg, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001192 if (!nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001193 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001194 }
Daniel Willmann5614e572021-01-18 18:38:27 +01001195 OSMO_ASSERT(nse->sgsn_facing);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001196 rc = gbprox_relay2nse(msg, nse, 0);
1197 break;
1198 }
Daniel Willmannf024eeb2021-07-06 14:02:41 +02001199 case BSSGP_PDUT_MS_REGISTR_ENQ:
1200 {
1201 struct gbproxy_sgsn *sgsn;
1202 struct osmo_mobile_identity mi;
1203 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1204 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
1205 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
1206
1207 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
1208 if (!sgsn) {
1209 LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN, dropping message!\n");
1210 rc = -EINVAL;
1211 break;
1212 }
1213
1214 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1215
1216 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
1217 break;
1218 }
Harald Weltee5209642020-12-05 19:59:45 +01001219 default:
1220 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001221 break;
1222 }
1223
Harald Weltee5209642020-12-05 19:59:45 +01001224 return rc;
Harald Welte560bdb32020-12-04 22:24:47 +01001225err_no_bvc:
Harald Weltee5209642020-12-05 19:59:45 +01001226 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 +02001227 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_NSEI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001228 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001229}
1230
1231/* Receive paging request from SGSN, we need to relay to proper BSS */
Harald Weltedf690e82020-12-12 15:58:28 +01001232static int gbprox_rx_paging(struct gbproxy_nse *sgsn_nse, struct msgb *msg, const char *pdut_name,
Daniel Willmann5614e572021-01-18 18:38:27 +01001233 struct tlv_parsed *tp, uint16_t ns_bvci, bool broadcast)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001234{
Harald Weltedf690e82020-12-12 15:58:28 +01001235 struct gbproxy_config *cfg = sgsn_nse->cfg;
Harald Weltee5209642020-12-05 19:59:45 +01001236 struct gbproxy_bvc *sgsn_bvc, *bss_bvc;
Harald Weltedf690e82020-12-12 15:58:28 +01001237 struct gbproxy_nse *nse;
Daniel Willmann76205712020-11-30 17:08:58 +01001238 unsigned int n_nses = 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001239 int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
Harald Welte8b4c7942020-12-05 10:14:49 +01001240 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001241
Harald Welte173a1822020-12-03 15:36:59 +01001242 if (TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001243 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001244 errctr = GBPROX_GLOB_CTR_OTHER_ERR;
Harald Weltedf690e82020-12-12 15:58:28 +01001245 sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
Harald Weltee5209642020-12-05 19:59:45 +01001246 if (!sgsn_bvc) {
Harald Weltedf690e82020-12-12 15:58:28 +01001247 LOGPNSE(sgsn_nse, LOGL_NOTICE, "Rx %s: unable to route: BVCI=%05u unknown\n",
Harald Weltee5209642020-12-05 19:59:45 +01001248 pdut_name, bvci);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001249 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001250 return -EINVAL;
1251 }
Harald Weltee5209642020-12-05 19:59:45 +01001252 LOGPBVC(sgsn_bvc, LOGL_INFO, "Rx %s: routing by BVCI\n", pdut_name);
1253 return gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Harald Welte173a1822020-12-03 15:36:59 +01001254 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {
Philipp Maierda3af942021-02-04 21:54:09 +01001255 struct gprs_ra_id raid;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001256 errctr = GBPROX_GLOB_CTR_INV_RAI;
Philipp Maierda3af942021-02-04 21:54:09 +01001257 gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
Harald Welte560bdb32020-12-04 22:24:47 +01001258 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001259 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001260 hash_for_each(nse->bvcs, j, bss_bvc, list) {
Philipp Maierda3af942021-02-04 21:54:09 +01001261 if (gsm48_ra_equal(&bss_bvc->raid, &raid)) {
Harald Weltee5209642020-12-05 19:59:45 +01001262 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (RAI match)\n",
1263 pdut_name);
1264 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001265 n_nses++;
1266 /* Only send it once to each NSE */
1267 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001268 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001269 }
1270 }
Harald Welte173a1822020-12-03 15:36:59 +01001271 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_LOCATION_AREA, 5)) {
Philipp Maierda3af942021-02-04 21:54:09 +01001272 struct gsm48_ra_id lac;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001273 errctr = GBPROX_GLOB_CTR_INV_LAI;
Harald Welte560bdb32020-12-04 22:24:47 +01001274 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001275 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001276 hash_for_each(nse->bvcs, j, bss_bvc, list) {
Philipp Maierda3af942021-02-04 21:54:09 +01001277 gsm48_encode_ra(&lac, &bss_bvc->raid);
1278 if (!memcmp(&lac, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
Harald Weltee5209642020-12-05 19:59:45 +01001279 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (LAI match)\n",
1280 pdut_name);
1281 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001282 n_nses++;
1283 /* Only send it once to each NSE */
1284 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001285 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001286 }
1287 }
Daniel Willmann5614e572021-01-18 18:38:27 +01001288 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1) || broadcast) {
Harald Welte560bdb32020-12-04 22:24:47 +01001289 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001290 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001291 hash_for_each(nse->bvcs, j, bss_bvc, list) {
1292 LOGPNSE(nse, LOGL_INFO, "Rx %s:routing to NSE (broadcast)\n", pdut_name);
1293 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001294 n_nses++;
1295 /* Only send it once to each NSE */
1296 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001297 }
Harald Welte53ee2062020-11-24 11:31:13 +01001298 }
1299 } else {
Harald Weltedf690e82020-12-12 15:58:28 +01001300 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, missing IE\n");
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001301 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Harald Welte53ee2062020-11-24 11:31:13 +01001302 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001303
Daniel Willmann76205712020-11-30 17:08:58 +01001304 if (n_nses == 0) {
Harald Weltedf690e82020-12-12 15:58:28 +01001305 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, no destination found\n");
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001306 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001307 return -EINVAL;
1308 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001309 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001310}
1311
1312/* Receive an incoming BVC-RESET message from the SGSN */
Harald Weltee5209642020-12-05 19:59:45 +01001313static int rx_bvc_reset_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp,
1314 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001315{
Harald Weltee5209642020-12-05 19:59:45 +01001316 uint16_t ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
1317 struct gbproxy_bvc *from_bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001318
Harald Weltee5209642020-12-05 19:59:45 +01001319 LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", ptp_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001320
Harald Weltee5209642020-12-05 19:59:45 +01001321 if (ptp_bvci == 0) {
1322 from_bvc = gbproxy_bvc_by_bvci(nse, 0);
1323 OSMO_ASSERT(from_bvc);
1324 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
1325 } else {
1326 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1327 if (!from_bvc) {
1328 LOGPNSE(nse, LOGL_ERROR, "Rx BVC-RESET BVCI=%05u: Cannot find BVC\n", ptp_bvci);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001329 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001330 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKNOWN_BVCI, &ptp_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001331 }
Harald Weltee5209642020-12-05 19:59:45 +01001332 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
Daniel Willmanne50550e2020-11-26 18:19:21 +01001333 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001334
1335 return 0;
1336}
1337
Philipp Maier1c5766b2021-02-09 17:03:03 +01001338/* Receive an incoming RIM message from the SGSN-side NS-VC */
1339static int gbprox_rx_rim_from_sgsn(struct tlv_parsed *tp, struct gbproxy_nse *nse, struct msgb *msg, char *log_pfx,
1340 const char *pdut_name)
1341{
1342 struct gbproxy_sgsn *sgsn;
1343 struct gbproxy_cell *dest_cell;
1344 struct bssgp_rim_routing_info dest_ri;
1345 struct bssgp_rim_routing_info src_ri;
1346 int rc;
Philipp Maier4499cf42021-02-10 17:54:44 +01001347 char ri_src_str[64];
1348 char ri_dest_str[64];
Daniel Willmannf8cba652021-02-12 04:59:47 +01001349 uint16_t ns_bvci = msgb_bvci(msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001350
1351 /* TODO: Reply with STATUS if BSSGP didn't negotiate RIM feature, see also comments in
1352 gbprox_rx_rim_from_bss() */
1353
1354 rc = bssgp_parse_rim_ri(&dest_ri, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
1355 TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
1356 if (rc < 0) {
1357 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse destination RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001358 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001359 }
1360 rc = bssgp_parse_rim_ri(&src_ri, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
1361 TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
1362 if (rc < 0) {
1363 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse source RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001364 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001365 }
1366
1367 /* Since gbproxy is 2G only we do not expect to get RIM messages that target non-GERAN cells. */
1368 if (dest_ri.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
1369 LOGP(DGPRS, LOGL_ERROR, "%s %s destination RIM routing info is not GERAN (%s)\n", log_pfx, pdut_name,
1370 bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001371 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001372 }
1373
1374 /* Lookup destination cell */
1375 dest_cell = gbproxy_cell_by_cellid(nse->cfg, &dest_ri.geran.raid, dest_ri.geran.cid);
1376 if (!dest_cell) {
1377 LOGP(DGPRS, LOGL_NOTICE, "%s %s cannot find cell for destination RIM routing info (%s)\n", log_pfx,
1378 pdut_name, bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001379 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001380 }
1381
1382 /* TODO: Check if the BVC of the destination cell actually did negotiate RIM support, see also comments
1383 * in gbprox_rx_rim_from_bss() */
1384 sgsn = gbproxy_sgsn_by_nsei(nse->cfg, nse->nsei);
1385 OSMO_ASSERT(sgsn);
1386
Philipp Maier4499cf42021-02-10 17:54:44 +01001387 LOGP(DLBSSGP, LOGL_DEBUG, "%s %s relaying from SGSN(%05u/%s) RIM-PDU: src=%s, dest=%s\n",
1388 log_pfx, pdut_name, sgsn->nse->nsei, sgsn->name,
1389 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &src_ri),
1390 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &dest_ri));
Philipp Maier1c5766b2021-02-09 17:03:03 +01001391
1392 return gbprox_relay2peer(msg, dest_cell->bss_bvc, 0);
1393}
1394
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001395/* Receive an incoming signalling message from the SGSN-side NS-VC */
Harald Weltedbef0aa2020-12-07 17:48:11 +01001396static 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 +02001397{
Harald Weltedbef0aa2020-12-07 17:48:11 +01001398 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001399 uint8_t pdu_type = bgph->pdu_type;
Harald Weltee5209642020-12-05 19:59:45 +01001400 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
1401 struct gbproxy_config *cfg = nse->cfg;
1402 struct gbproxy_bvc *sgsn_bvc;
Philipp Maier74882dc2021-02-04 16:31:46 +01001403 struct tlv_parsed tp[2];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001404 int data_len;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001405 uint16_t bvci;
Harald Welteec0f8012020-12-06 16:32:01 +01001406 char log_pfx[32];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001407 int rc = 0;
Harald Welted2fef952020-12-05 00:31:07 +01001408 int i;
Daniel Willmann5614e572021-01-18 18:38:27 +01001409 bool paging_bc = false;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001410
Harald Weltee5209642020-12-05 19:59:45 +01001411 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);
1412
1413 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welteec0f8012020-12-06 16:32:01 +01001414
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001415 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welteec0f8012020-12-06 16:32:01 +01001416 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001417 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001418 }
1419
Harald Welte278dd272020-12-06 13:35:24 +01001420 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Weltee5209642020-12-05 19:59:45 +01001421 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001422 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +01001423 }
1424
1425 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_DL)) {
Harald Weltee5209642020-12-05 19:59:45 +01001426 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001427 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001428 }
1429
Harald Weltedbef0aa2020-12-07 17:48:11 +01001430 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welteec0f8012020-12-06 16:32:01 +01001431
Philipp Maier74882dc2021-02-04 16:31:46 +01001432 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 +01001433 DGPRS, log_pfx);
1434 if (rc < 0) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001435 rc = tx_status_from_tlvp(nse, rc, msg);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001436 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_SGSN));
Harald Welteec0f8012020-12-06 16:32:01 +01001437 return rc;
1438 }
Harald Weltee5209642020-12-05 19:59:45 +01001439 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
Philipp Maier74882dc2021-02-04 16:31:46 +01001440 msgb_bcid(msg) = (void *)tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001441
1442 switch (pdu_type) {
1443 case BSSGP_PDUT_BVC_RESET:
Harald Weltee5209642020-12-05 19:59:45 +01001444 /* resolve or create ggbproxy_bvc + handle in BVC-FSM */
Philipp Maier74882dc2021-02-04 16:31:46 +01001445 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1446 rc = rx_bvc_reset_from_sgsn(nse, msg, &tp[0], ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001447 break;
1448 case BSSGP_PDUT_BVC_RESET_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001449 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001450 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1451 if (!sgsn_bvc)
1452 goto err_no_bvc;
1453 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
1454 break;
1455 case BSSGP_PDUT_BVC_BLOCK_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001456 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001457 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
Daniel Willmanndc763fd2021-09-24 16:45:38 +02001458 if (!sgsn_bvc) {
1459 /* Check if BVC was blocked before */
1460 sgsn_bvc = gbproxy_bvc_by_bvci_inactive(nse, bvci);
1461 if (!sgsn_bvc)
1462 goto err_no_bvc;
1463 }
Harald Weltee5209642020-12-05 19:59:45 +01001464 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK_ACK, msg);
1465 break;
1466 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001467 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001468 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1469 if (!sgsn_bvc)
1470 goto err_no_bvc;
1471 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK_ACK, msg);
Daniel Willmann8489e7a2020-11-03 21:12:42 +01001472 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001473 case BSSGP_PDUT_FLUSH_LL:
1474 /* simple case: BVCI IE is mandatory */
Philipp Maier74882dc2021-02-04 16:31:46 +01001475 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001476 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1477 if (!sgsn_bvc)
1478 goto err_no_bvc;
1479 if (sgsn_bvc->cell && sgsn_bvc->cell->bss_bvc)
1480 rc = gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001481 break;
Daniel Willmann5614e572021-01-18 18:38:27 +01001482 case BSSGP_PDUT_DUMMY_PAGING_PS:
1483 /* Routing area is optional in dummy paging and we have nothing else to go by
1484 * so in case it is missing we need to broadcast the paging */
1485 paging_bc = true;
1486 /* fall through */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001487 case BSSGP_PDUT_PAGING_PS:
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001488 {
1489 /* Cache the IMSI<->NSE to route PAGING REJECT */
1490 struct osmo_mobile_identity mi;
Philipp Maier74882dc2021-02-04 16:31:46 +01001491 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1492 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001493 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +02001494 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001495 /* fall through */
1496 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001497 case BSSGP_PDUT_PAGING_CS:
1498 /* process the paging request (LAI/RAI lookup) */
Philipp Maier74882dc2021-02-04 16:31:46 +01001499 rc = gbprox_rx_paging(nse, msg, pdut_name, &tp[0], ns_bvci, paging_bc);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001500 break;
1501 case BSSGP_PDUT_STATUS:
Daniel Willmann885f4302021-09-30 16:58:46 +02001502 {
1503 struct gbproxy_nse *nse_peer;
1504 uint32_t tlli;
1505
1506 /* Check if the status needs to be terminated locally */
1507 uint8_t cause = *TLVP_VAL(&tp[0], BSSGP_IE_CAUSE);
1508
1509 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI || cause == BSSGP_CAUSE_BVCI_BLOCKED) {
1510 /* Log and handle locally, BVCI should be present for these causes */
1511 if (!TLVP_PRESENT(&tp[0], BSSGP_IE_BVCI)) {
1512 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s), but BVCI is missing\n", cause,
1513 bssgp_cause_str(cause));
1514 break;
1515 }
1516 uint16_t ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1517 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s) for PtP-BVC %05u\n", cause,
1518 bssgp_cause_str(cause), ptp_bvci);
1519 /* FIXME: Remove/block the other BSS/SGSN BVCs if present? */
1520 break;
1521 }
1522
1523 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s)\n", cause,
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001524 bssgp_cause_str(cause));
Daniel Willmann885f4302021-09-30 16:58:46 +02001525
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001526
1527 if (gbproxy_bvci_from_status_pdu(tp, &bvci, log_pfx) == 0 && bvci != 0) {
1528 struct gbproxy_cell *cell = gbproxy_cell_by_bvci(cfg, bvci);
1529
1530 if ((!cell || !cell->bss_bvc || !cell->bss_bvc->nse)) {
1531 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s), but can't find NSE for cell\n",
1532 cause, bssgp_cause_str(cause));
1533 break;
1534 }
1535
1536 return gbprox_relay2nse(msg, cell->bss_bvc->nse, 0);
1537 }
1538
Daniel Willmann6ec5f952021-10-28 16:13:03 +02001539 /* We can only forward this TLLI if it's in the cache (which only happens on suspend/resume) */
1540 if (gbproxy_tlli_from_status_pdu(tp, &tlli, log_pfx) == 0) {
Daniel Willmann885f4302021-09-30 16:58:46 +02001541 nse_peer = gbproxy_nse_by_tlli(cfg, tlli);
1542 if (nse_peer)
1543 return gbprox_relay2nse(msg, nse_peer, 0);
1544 }
1545
1546 LOGPNSE(nse, LOGL_ERROR, "Unable to handle STATUS cause=0x%02x(%s)\n", cause,
1547 bssgp_cause_str(cause));
1548
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001549 break;
Daniel Willmann885f4302021-09-30 16:58:46 +02001550 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001551 /* those only exist in the SGSN -> BSS direction */
1552 case BSSGP_PDUT_SUSPEND_ACK:
1553 case BSSGP_PDUT_SUSPEND_NACK:
1554 case BSSGP_PDUT_RESUME_ACK:
1555 case BSSGP_PDUT_RESUME_NACK:
Daniel Willmann77493b12020-12-29 21:13:31 +01001556 {
1557 struct gbproxy_nse *nse_peer;
Philipp Maier74882dc2021-02-04 16:31:46 +01001558 uint32_t tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Daniel Willmann77493b12020-12-29 21:13:31 +01001559
1560 nse_peer = gbproxy_nse_by_tlli(cfg, tlli);
1561 if (!nse_peer) {
1562 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);
1563 /* TODO: Counter */
Daniel Willmannf8cba652021-02-12 04:59:47 +01001564 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Daniel Willmann77493b12020-12-29 21:13:31 +01001565 }
1566 /* Delete the entry after we're done */
1567 gbproxy_tlli_cache_remove(cfg, tlli);
1568 LOGPNSE(nse_peer, LOGL_DEBUG, "Rx %s: forwarding\n", pdut_name);
1569 gbprox_relay2nse(msg, nse_peer, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001570 break;
Daniel Willmann77493b12020-12-29 21:13:31 +01001571 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001572 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
Harald Welte7479c4d2020-12-02 20:06:04 +01001573 case BSSGP_PDUT_OVERLOAD:
Harald Weltee5209642020-12-05 19:59:45 +01001574 LOGPNSE(nse, LOGL_DEBUG, "Rx %s: broadcasting\n", pdut_name);
Harald Welte560bdb32020-12-04 22:24:47 +01001575 /* broadcast to all BSS-side bvcs */
Harald Welted2fef952020-12-05 00:31:07 +01001576 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte7479c4d2020-12-02 20:06:04 +01001577 gbprox_relay2nse(msg, nse, 0);
1578 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001579 break;
Harald Weltee5209642020-12-05 19:59:45 +01001580 case BSSGP_PDUT_RAN_INFO:
1581 case BSSGP_PDUT_RAN_INFO_REQ:
1582 case BSSGP_PDUT_RAN_INFO_ACK:
1583 case BSSGP_PDUT_RAN_INFO_ERROR:
1584 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
Philipp Maier1c5766b2021-02-09 17:03:03 +01001585 rc = gbprox_rx_rim_from_sgsn(tp, nse, msg, log_pfx, pdut_name);
Pau Espin Pedrola4296342021-05-07 13:33:34 +02001586 break;
Daniel Willmannf024eeb2021-07-06 14:02:41 +02001587 case BSSGP_PDUT_MS_REGISTR_ENQ_RESP:
1588 {
1589 struct gbproxy_nse *nse_peer;
1590 struct osmo_mobile_identity mi;
1591 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1592 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
1593 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
1594 nse_peer = gbproxy_nse_by_imsi(cfg, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1595 if (!nse_peer) {
1596 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);
1597 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
1598 } else if (nse_peer->sgsn_facing) {
1599 LOGPNSE(nse, LOGL_ERROR, "Forwarding %s failed: IMSI cache contains SGSN NSE", pdut_name);
1600 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
1601 }
1602 gbproxy_imsi_cache_remove(cfg, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1603 gbprox_relay2nse(msg, nse_peer, ns_bvci);
1604 break;
1605 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001606 default:
Harald Weltee5209642020-12-05 19:59:45 +01001607 LOGPNSE(nse, LOGL_NOTICE, "Rx %s: Not supported\n", pdut_name);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001608 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_SGSN));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001609 rc = tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001610 break;
1611 }
1612
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001613 return rc;
Harald Weltee5209642020-12-05 19:59:45 +01001614
Harald Welte560bdb32020-12-04 22:24:47 +01001615err_no_bvc:
Daniel Willmann723bb362021-09-28 18:51:47 +02001616 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find BVC %05u\n", pdut_name, bvci);
Daniel Willmannc4b913b2021-09-24 16:43:42 +02001617 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001618 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001619}
1620
Harald Weltee5209642020-12-05 19:59:45 +01001621
1622/***********************************************************************
1623 * libosmogb NS/BSSGP integration
1624 ***********************************************************************/
1625
Alexander Couzens951e1332020-09-22 13:21:46 +02001626int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001627{
1628 int rc;
Alexander Couzens951e1332020-09-22 13:21:46 +02001629 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
1630 struct gprs_ns2_inst *nsi = cfg->nsi;
1631 struct osmo_gprs_ns2_prim nsp = {};
1632
1633 nsp.bvci = msgb_bvci(msg);
1634 nsp.nsei = msgb_nsei(msg);
1635
Alexander Couzens55c36f92021-01-27 20:56:55 +01001636 osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
Alexander Couzens951e1332020-09-22 13:21:46 +02001637 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
1638
1639 return rc;
1640}
1641
1642/* Main input function for Gb proxy */
1643int gbprox_rcvmsg(void *ctx, struct msgb *msg)
1644{
Alexander Couzens951e1332020-09-22 13:21:46 +02001645 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Harald Weltee5209642020-12-05 19:59:45 +01001646 uint16_t ns_bvci = msgb_bvci(msg);
1647 uint16_t nsei = msgb_nsei(msg);
1648 struct gbproxy_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001649
Harald Weltee5209642020-12-05 19:59:45 +01001650 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_SGSN);
1651 if (nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001652 /* ensure minimum length to decode PDU type */
1653 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
1654 return tx_status(nse, ns_bvci, BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
1655
Harald Weltee5209642020-12-05 19:59:45 +01001656 if (ns_bvci == 0 || ns_bvci == 1)
1657 return gbprox_rx_sig_from_sgsn(nse, msg, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001658 else
Harald Weltee5209642020-12-05 19:59:45 +01001659 return gbprox_rx_ptp_from_sgsn(nse, msg, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001660 }
1661
Harald Weltee5209642020-12-05 19:59:45 +01001662 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_BSS);
1663 if (!nse) {
1664 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) not known -> allocating\n", nsei);
1665 nse = gbproxy_nse_alloc(cfg, nsei, false);
1666 }
1667 if (nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001668 /* ensure minimum length to decode PDU type */
1669 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
1670 return tx_status(nse, ns_bvci, BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
1671
Harald Weltee5209642020-12-05 19:59:45 +01001672 if (ns_bvci == 0 || ns_bvci == 1)
1673 return gbprox_rx_sig_from_bss(nse, msg, ns_bvci);
1674 else
1675 return gbprox_rx_ptp_from_bss(nse, msg, ns_bvci);
1676 }
1677
1678 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001679}
1680
Alexander Couzens951e1332020-09-22 13:21:46 +02001681/* TODO: What about handling:
Alexander Couzens55c36f92021-01-27 20:56:55 +01001682 * GPRS_NS2_AFF_CAUSE_VC_FAILURE,
1683 GPRS_NS2_AFF_CAUSE_VC_RECOVERY,
Alexander Couzens951e1332020-09-22 13:21:46 +02001684 osmocom own causes
Alexander Couzens55c36f92021-01-27 20:56:55 +01001685 GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED,
1686 GPRS_NS2_AFF_CAUSE_SNS_FAILURE,
Alexander Couzens951e1332020-09-22 13:21:46 +02001687 */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001688
Alexander Couzens951e1332020-09-22 13:21:46 +02001689void gprs_ns_prim_status_cb(struct gbproxy_config *cfg, struct osmo_gprs_ns2_prim *nsp)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001690{
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001691 int i;
Harald Welte560bdb32020-12-04 22:24:47 +01001692 struct gbproxy_bvc *bvc;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001693 struct gbproxy_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001694
Alexander Couzens951e1332020-09-22 13:21:46 +02001695 switch (nsp->u.status.cause) {
Alexander Couzens55c36f92021-01-27 20:56:55 +01001696 case GPRS_NS2_AFF_CAUSE_SNS_FAILURE:
1697 case GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED:
Alexander Couzens951e1332020-09-22 13:21:46 +02001698 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001699
Alexander Couzens55c36f92021-01-27 20:56:55 +01001700 case GPRS_NS2_AFF_CAUSE_RECOVERY:
Harald Welte9b367d22021-01-18 13:55:51 +01001701 LOGP(DGPRS, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);
Daniel Willmannf96cac52021-03-09 16:14:18 +01001702 nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_SGSN);
1703 if (nse) {
Daniel Willmann37518b32021-05-27 18:13:36 +02001704 nse->alive = true;
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001705 // Update the NSE max SDU len
Daniel Willmannf96cac52021-03-09 16:14:18 +01001706 nse->max_sdu_len = nsp->u.status.mtu;
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001707
Harald Weltee5209642020-12-05 19:59:45 +01001708 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001709 bvc = gbproxy_bvc_by_bvci(nse, 0);
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001710 if (bvc) {
Daniel Willmannf96cac52021-03-09 16:14:18 +01001711 bssgp_bvc_fsm_set_max_pdu_len(bvc->fi, nse->max_sdu_len);
Daniel Willmann3ea37932021-02-10 13:41:14 +01001712 osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001713 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001714 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001715 break;
Alexander Couzens55c36f92021-01-27 20:56:55 +01001716 case GPRS_NS2_AFF_CAUSE_FAILURE:
Daniel Willmannf96cac52021-03-09 16:14:18 +01001717 nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_BSS | NSE_F_SGSN);
1718 if (!nse) {
1719 LOGP(DGPRS, LOGL_ERROR, "Unknown NSE(%05d) became unavailable\n", nsp->nsei);
1720 break;
1721 }
Daniel Willmann37518b32021-05-27 18:13:36 +02001722
1723 nse->alive = false;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001724 if (nse->sgsn_facing) {
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001725 struct hlist_node *ntmp;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001726 /* SGSN */
1727 /* TODO: When to block all PtP towards bss? Only if all SGSN are down? */
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001728 hash_for_each_safe(nse->bvcs, i, ntmp, bvc, list) {
1729 if (bvc->bvci == 0)
1730 continue;
1731 gbproxy_bvc_free(bvc);
1732 }
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001733 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_RESTART_RESET_SGSN));
Alexander Couzens951e1332020-09-22 13:21:46 +02001734 } else {
Daniel Willmannf96cac52021-03-09 16:14:18 +01001735 /* BSS became unavailable
1736 * Block matching PtP-BVCs on SGSN-side */
1737 hash_for_each(nse->bvcs, i, bvc, list) {
1738 if (bvc->bvci == 0)
1739 continue;
1740 /* Get BVC for each SGSN and send block request */
1741 struct gbproxy_cell *cell = bvc->cell;
1742 for (int j = 0; j < GBPROXY_MAX_NR_SGSN; j++) {
1743 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[j];
1744 if (!sgsn_bvc)
1745 continue;
1746
1747 /* Block BVC, indicate BSS equipment failure */
1748 uint8_t cause = BSSGP_CAUSE_EQUIP_FAIL;
1749 osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
Daniel Willmanndc763fd2021-09-24 16:45:38 +02001750 sgsn_bvc->inactive = true;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001751 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001752 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001753
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001754 /* This frees the BVCs for us as well */
1755 gbproxy_nse_free(nse);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001756 }
Harald Welte9b367d22021-01-18 13:55:51 +01001757 LOGP(DGPRS, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);
Alexander Couzens951e1332020-09-22 13:21:46 +02001758 break;
1759 default:
Harald Welte9b367d22021-01-18 13:55:51 +01001760 LOGP(DGPRS, LOGL_NOTICE, "NS: Unknown NS-STATUS.ind cause=%s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001761 gprs_ns2_aff_cause_prim_str(nsp->u.status.cause));
Alexander Couzens951e1332020-09-22 13:21:46 +02001762 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001763 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001764}
1765
Alexander Couzens951e1332020-09-22 13:21:46 +02001766/* called by the ns layer */
1767int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
1768{
1769 struct osmo_gprs_ns2_prim *nsp;
1770 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Daniel Willmann8f407b12020-12-02 19:33:50 +01001771 uintptr_t bvci;
Alexander Couzens951e1332020-09-22 13:21:46 +02001772 int rc = 0;
1773
1774 if (oph->sap != SAP_NS)
1775 return 0;
1776
1777 nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
1778
1779 if (oph->operation != PRIM_OP_INDICATION) {
Harald Welte9b367d22021-01-18 13:55:51 +01001780 LOGP(DGPRS, LOGL_NOTICE, "NS: Unexpected primitive operation %s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001781 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +02001782 return 0;
1783 }
1784
1785 switch (oph->primitive) {
Alexander Couzens55c36f92021-01-27 20:56:55 +01001786 case GPRS_NS2_PRIM_UNIT_DATA:
Daniel Willmann8f407b12020-12-02 19:33:50 +01001787
Alexander Couzens951e1332020-09-22 13:21:46 +02001788 /* hand the message into the BSSGP implementation */
1789 msgb_bssgph(oph->msg) = oph->msg->l3h;
1790 msgb_bvci(oph->msg) = nsp->bvci;
1791 msgb_nsei(oph->msg) = nsp->nsei;
Daniel Willmann8f407b12020-12-02 19:33:50 +01001792 bvci = nsp->bvci | BVC_LOG_CTX_FLAG;
Alexander Couzens951e1332020-09-22 13:21:46 +02001793
Daniel Willmann8f407b12020-12-02 19:33:50 +01001794 log_set_context(LOG_CTX_GB_BVC, (void *)bvci);
Alexander Couzens951e1332020-09-22 13:21:46 +02001795 rc = gbprox_rcvmsg(cfg, oph->msg);
Daniel Willmannb6550102020-11-04 17:32:56 +01001796 msgb_free(oph->msg);
Alexander Couzens951e1332020-09-22 13:21:46 +02001797 break;
Alexander Couzens55c36f92021-01-27 20:56:55 +01001798 case GPRS_NS2_PRIM_STATUS:
Alexander Couzens951e1332020-09-22 13:21:46 +02001799 gprs_ns_prim_status_cb(cfg, nsp);
1800 break;
1801 default:
Harald Welte9b367d22021-01-18 13:55:51 +01001802 LOGP(DGPRS, LOGL_NOTICE, "NS: Unknown prim %s %s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001803 gprs_ns2_prim_str(oph->primitive),
1804 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +02001805 break;
1806 }
1807
1808 return rc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001809}
1810
1811void gbprox_reset(struct gbproxy_config *cfg)
1812{
Harald Welted2fef952020-12-05 00:31:07 +01001813 struct gbproxy_nse *nse;
1814 struct hlist_node *ntmp;
Harald Welte8b4c7942020-12-05 10:14:49 +01001815 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001816
Harald Welted2fef952020-12-05 00:31:07 +01001817 hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +01001818 struct gbproxy_bvc *bvc;
1819 struct hlist_node *tmp;
1820 hash_for_each_safe(nse->bvcs, j, tmp, bvc, list)
Harald Welte560bdb32020-12-04 22:24:47 +01001821 gbproxy_bvc_free(bvc);
Daniel Willmanne50550e2020-11-26 18:19:21 +01001822
1823 gbproxy_nse_free(nse);
1824 }
Harald Weltee5209642020-12-05 19:59:45 +01001825 /* FIXME: cells */
1826 /* FIXME: SGSN side BVCs (except signaling) */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001827
1828 rate_ctr_group_free(cfg->ctrg);
1829 gbproxy_init_config(cfg);
1830}
1831
Daniel Willmann77493b12020-12-29 21:13:31 +01001832static void tlli_cache_cleanup(void *data)
1833{
1834 struct gbproxy_config *cfg = data;
1835 gbproxy_tlli_cache_cleanup(cfg);
1836
1837 /* TODO: Disable timer when cache is empty */
1838 osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);
1839}
1840
Daniel Willmannc8a50092021-01-17 13:11:41 +01001841static void imsi_cache_cleanup(void *data)
1842{
1843 struct gbproxy_config *cfg = data;
1844 gbproxy_imsi_cache_cleanup(cfg);
1845
1846 /* TODO: Disable timer when cache is empty */
1847 osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0);
1848}
1849
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001850int gbproxy_init_config(struct gbproxy_config *cfg)
1851{
1852 struct timespec tp;
1853
Harald Welte209dc9f2020-12-12 19:02:16 +01001854 /* by default we advertise 100% of the BSS-side capacity to _each_ SGSN */
1855 cfg->pool.bvc_fc_ratio = 100;
Daniel Willmannee834af2020-12-14 16:22:39 +01001856 cfg->pool.null_nri_ranges = osmo_nri_ranges_alloc(cfg);
Daniel Willmann77493b12020-12-29 21:13:31 +01001857 /* TODO: Make configurable */
Daniel Willmannbd12f3f2021-01-13 18:16:04 +01001858 cfg->tlli_cache.timeout = 10;
Daniel Willmannc8a50092021-01-17 13:11:41 +01001859 cfg->imsi_cache.timeout = 10;
Daniel Willmannee834af2020-12-14 16:22:39 +01001860
Harald Welted2fef952020-12-05 00:31:07 +01001861 hash_init(cfg->bss_nses);
Daniel Willmann1e7be5d2020-12-21 18:08:21 +01001862 hash_init(cfg->sgsn_nses);
1863 hash_init(cfg->cells);
Daniel Willmann77493b12020-12-29 21:13:31 +01001864 hash_init(cfg->tlli_cache.entries);
Daniel Willmannee834af2020-12-14 16:22:39 +01001865 INIT_LLIST_HEAD(&cfg->sgsns);
1866
Daniel Willmann77493b12020-12-29 21:13:31 +01001867 osmo_timer_setup(&cfg->tlli_cache.timer, tlli_cache_cleanup, cfg);
1868 osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);
1869
Daniel Willmannc8a50092021-01-17 13:11:41 +01001870 /* We could also combine both timers */
1871 osmo_timer_setup(&cfg->imsi_cache.timer, imsi_cache_cleanup, cfg);
1872 osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0);
1873
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001874 cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
1875 if (!cfg->ctrg) {
1876 LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
1877 return -1;
1878 }
1879 osmo_clock_gettime(CLOCK_REALTIME, &tp);
Harald Weltec169de42020-12-07 13:12:13 +01001880 osmo_fsm_log_timeouts(true);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001881
1882 return 0;
Oliver Smith29532c22021-01-29 11:13:00 +01001883}