blob: 5d9219d6e698841dafe18f8f95905e331bc2af9b [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 Willmann7d37cbb2021-09-29 11:51:51 +0200992static int gbproxy_tlli_from_status_pdu(struct msgb *msg, struct tlv_parsed *tp, uint32_t *tlli, char *log_pfx)
993{
994 int rc;
995 int pdu_len = TLVP_LEN(&tp[0], BSSGP_IE_PDU_IN_ERROR);
996 const uint8_t *pdu_data = TLVP_VAL(&tp[0], BSSGP_IE_PDU_IN_ERROR);
997 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)pdu_data;
998 struct tlv_parsed tp_inner[2];
999
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001000 /* TODO: Parse partial messages as well */
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001001 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp_inner, ARRAY_SIZE(tp_inner), bgph->pdu_type, bgph->data,
1002 pdu_len - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
1003
1004 if (rc < 0)
1005 return rc;
1006
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +02001007 if (TLVP_PRESENT(&tp_inner[0], BSSGP_IE_TLLI)) {
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001008 *tlli = osmo_load32be(TLVP_VAL(&tp_inner[0], BSSGP_IE_TLLI));
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +02001009 } else if (TLVP_PRESENT(&tp_inner[0], BSSGP_IE_TMSI)) {
1010 /* we treat the TMSI like a TLLI and extract the NRI from it */
1011 *tlli = osmo_load32be(TLVP_VAL(&tp_inner[0], BSSGP_IE_TMSI));
1012 /* Convert the TMSI into a FOREIGN TLLI so it is routed appropriately */
1013 *tlli = gprs_tmsi2tlli(*tlli, TLLI_FOREIGN);
1014 } else {
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001015 return -ENOENT;
Daniel Willmanncbfc7cf2021-09-29 11:51:56 +02001016 }
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001017
1018 return 0;
1019}
1020
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001021/* Extract the BVCI from the PDU-in-error of the STATUS PDU (if available) */
1022static int gbproxy_bvci_from_status_pdu(struct tlv_parsed *tp, uint16_t *bvci, char *log_pfx)
1023{
1024 int rc;
1025 int pdu_len = TLVP_LEN(&tp[0], BSSGP_IE_PDU_IN_ERROR);
1026 const uint8_t *pdu_data = TLVP_VAL(&tp[0], BSSGP_IE_PDU_IN_ERROR);
1027 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)pdu_data;
1028 struct tlv_parsed tp_inner[2];
1029
1030 /* TODO: Parse partial messages as well */
1031 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp_inner, ARRAY_SIZE(tp_inner), bgph->pdu_type, bgph->data,
1032 pdu_len - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
1033
1034 if (rc < 0)
1035 return rc;
1036
1037 if (TLVP_PRESENT(&tp_inner[0], BSSGP_IE_BVCI))
1038 *bvci = ntohs(tlvp_val16_unal(&tp_inner[0], BSSGP_IE_BVCI));
1039 else
1040 return -ENOENT;
1041
1042 return 0;
1043}
1044
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001045/* Receive an incoming signalling message from a BSS-side NS-VC */
Harald Weltee5209642020-12-05 19:59:45 +01001046static 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 +02001047{
1048 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001049 uint8_t pdu_type = bgph->pdu_type;
Harald Weltee5209642020-12-05 19:59:45 +01001050 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
Philipp Maier74882dc2021-02-04 16:31:46 +01001051 struct tlv_parsed tp[2];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001052 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welte560bdb32020-12-04 22:24:47 +01001053 struct gbproxy_bvc *from_bvc = NULL;
Harald Welteec0f8012020-12-06 16:32:01 +01001054 char log_pfx[32];
Harald Weltee5209642020-12-05 19:59:45 +01001055 uint16_t ptp_bvci;
1056 uint32_t tlli;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001057 int rc;
1058
Harald Weltee5209642020-12-05 19:59:45 +01001059 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);
1060
1061 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welteec0f8012020-12-06 16:32:01 +01001062
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001063 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Weltee5209642020-12-05 19:59:45 +01001064 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 +01001065 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001066 }
1067
Harald Welte278dd272020-12-06 13:35:24 +01001068 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Weltee5209642020-12-05 19:59:45 +01001069 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001070 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +01001071 }
1072
1073 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_UL)) {
Harald Weltee5209642020-12-05 19:59:45 +01001074 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001075 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001076 }
1077
Philipp Maier74882dc2021-02-04 16:31:46 +01001078 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 +01001079 DGPRS, log_pfx);
1080 if (rc < 0) {
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001081 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_BSS));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001082 return tx_status_from_tlvp(nse, rc, msg);
Harald Welteec0f8012020-12-06 16:32:01 +01001083 }
Harald Weltee5209642020-12-05 19:59:45 +01001084 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
Philipp Maier74882dc2021-02-04 16:31:46 +01001085 msgb_bcid(msg) = (void *)tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001086
Harald Weltee5209642020-12-05 19:59:45 +01001087 /* special case handling for some PDU types */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001088 switch (pdu_type) {
Harald Weltee5209642020-12-05 19:59:45 +01001089 case BSSGP_PDUT_BVC_RESET:
1090 /* resolve or create gbproxy_bvc + handlei n BVC-FSM */
Philipp Maier74882dc2021-02-04 16:31:46 +01001091 return rx_bvc_reset_from_bss(nse, msg, &tp[0]);
Harald Weltee5209642020-12-05 19:59:45 +01001092 case BSSGP_PDUT_BVC_RESET_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001093 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001094 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
Harald Welte560bdb32020-12-04 22:24:47 +01001095 if (!from_bvc)
1096 goto err_no_bvc;
Harald Weltee5209642020-12-05 19:59:45 +01001097 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
1098 case BSSGP_PDUT_BVC_BLOCK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001099 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001100 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1101 if (!from_bvc)
1102 goto err_no_bvc;
1103 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK, msg);
1104 case BSSGP_PDUT_BVC_UNBLOCK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001105 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001106 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1107 if (!from_bvc)
1108 goto err_no_bvc;
1109 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK, msg);
1110 case BSSGP_PDUT_SUSPEND:
1111 case BSSGP_PDUT_RESUME:
Daniel Willmann77493b12020-12-29 21:13:31 +01001112 {
1113 struct gbproxy_sgsn *sgsn;
1114
Philipp Maier74882dc2021-02-04 16:31:46 +01001115 tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Daniel Willmann77493b12020-12-29 21:13:31 +01001116 sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
1117 if (!sgsn) {
1118 LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN for TLLI, dropping message!\n");
1119 rc = -EINVAL;
1120 break;
1121 }
1122
1123 gbproxy_tlli_cache_update(nse, tlli);
1124
1125 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
Harald Weltee5209642020-12-05 19:59:45 +01001126#if 0
1127 /* TODO: Validate the RAI for consistency with the RAI
1128 * we expect for any of the BVC within this BSS side NSE */
Philipp Maier74882dc2021-02-04 16:31:46 +01001129 memcpy(ra, TLVP_VAL(&tp[0], BSSGP_IE_ROUTEING_AREA), sizeof(from_bvc->ra));
Harald Welte560bdb32020-12-04 22:24:47 +01001130 gsm48_parse_ra(&raid, from_bvc->ra);
Harald Weltee5209642020-12-05 19:59:45 +01001131#endif
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001132 break;
Daniel Willmann77493b12020-12-29 21:13:31 +01001133 }
Harald Weltee5209642020-12-05 19:59:45 +01001134 case BSSGP_PDUT_STATUS:
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001135 {
1136 struct gbproxy_sgsn *sgsn;
1137 /* Check if the status needs to be terminated locally */
1138 uint8_t cause = *TLVP_VAL(&tp[0], BSSGP_IE_CAUSE);
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001139
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001140 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI || cause == BSSGP_CAUSE_BVCI_BLOCKED) {
1141 /* Log and handle locally */
1142 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001143 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s) for PtP-BVC %05u\n", cause,
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001144 bssgp_cause_str(cause), ptp_bvci);
1145 /* FIXME: Remove/block our BVC if present? */
1146 break;
1147 }
1148
Daniel Willmannc5dcebd2021-09-30 16:57:51 +02001149 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s) ", cause,
1150 bssgp_cause_str(cause));
1151
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001152 if (gbproxy_tlli_from_status_pdu(msg, tp, &tlli, log_pfx) == 0)
1153 sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
1154 else
1155 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
1156
1157 if (!sgsn) {
1158 rc = -EINVAL;
1159 break;
1160 }
1161
1162 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
Harald Weltee5209642020-12-05 19:59:45 +01001163 break;
Daniel Willmann7d37cbb2021-09-29 11:51:51 +02001164 }
Harald Weltee5209642020-12-05 19:59:45 +01001165 case BSSGP_PDUT_RAN_INFO:
1166 case BSSGP_PDUT_RAN_INFO_REQ:
1167 case BSSGP_PDUT_RAN_INFO_ACK:
1168 case BSSGP_PDUT_RAN_INFO_ERROR:
1169 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
Philipp Maier1c5766b2021-02-09 17:03:03 +01001170 rc = gbprox_rx_rim_from_bss(tp, nse, msg, log_pfx, pdut_name);
Harald Weltee5209642020-12-05 19:59:45 +01001171 break;
1172 case BSSGP_PDUT_LLC_DISCARD:
1173 case BSSGP_PDUT_FLUSH_LL_ACK:
1174 /* route based on BVCI + TLLI */
Philipp Maier74882dc2021-02-04 16:31:46 +01001175 ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1176 tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Harald Weltee5209642020-12-05 19:59:45 +01001177 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1178 if (!from_bvc)
1179 goto err_no_bvc;
Daniel Willmannd4ab1f92020-12-21 18:53:55 +01001180 gbprox_bss2sgsn_tlli(from_bvc->cell, msg, &tlli, true);
Harald Weltee5209642020-12-05 19:59:45 +01001181 break;
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001182 case BSSGP_PDUT_PAGING_PS_REJECT:
Daniel Willmann5614e572021-01-18 18:38:27 +01001183 case BSSGP_PDUT_DUMMY_PAGING_PS_RESP:
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001184 {
1185 /* Route according to IMSI<->NSE cache entry */
1186 struct osmo_mobile_identity mi;
Philipp Maier74882dc2021-02-04 16:31:46 +01001187 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1188 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001189 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +02001190 nse = gbproxy_nse_by_imsi(nse->cfg, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001191 if (!nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001192 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001193 }
Daniel Willmann5614e572021-01-18 18:38:27 +01001194 OSMO_ASSERT(nse->sgsn_facing);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001195 rc = gbprox_relay2nse(msg, nse, 0);
1196 break;
1197 }
Daniel Willmannf024eeb2021-07-06 14:02:41 +02001198 case BSSGP_PDUT_MS_REGISTR_ENQ:
1199 {
1200 struct gbproxy_sgsn *sgsn;
1201 struct osmo_mobile_identity mi;
1202 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1203 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
1204 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
1205
1206 sgsn = gbproxy_select_sgsn(nse->cfg, NULL);
1207 if (!sgsn) {
1208 LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN, dropping message!\n");
1209 rc = -EINVAL;
1210 break;
1211 }
1212
1213 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1214
1215 rc = gbprox_relay2nse(msg, sgsn->nse, 0);
1216 break;
1217 }
Harald Weltee5209642020-12-05 19:59:45 +01001218 default:
1219 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001220 break;
1221 }
1222
Harald Weltee5209642020-12-05 19:59:45 +01001223 return rc;
Harald Welte560bdb32020-12-04 22:24:47 +01001224err_no_bvc:
Harald Weltee5209642020-12-05 19:59:45 +01001225 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 +02001226 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_NSEI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001227 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001228}
1229
1230/* Receive paging request from SGSN, we need to relay to proper BSS */
Harald Weltedf690e82020-12-12 15:58:28 +01001231static int gbprox_rx_paging(struct gbproxy_nse *sgsn_nse, struct msgb *msg, const char *pdut_name,
Daniel Willmann5614e572021-01-18 18:38:27 +01001232 struct tlv_parsed *tp, uint16_t ns_bvci, bool broadcast)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001233{
Harald Weltedf690e82020-12-12 15:58:28 +01001234 struct gbproxy_config *cfg = sgsn_nse->cfg;
Harald Weltee5209642020-12-05 19:59:45 +01001235 struct gbproxy_bvc *sgsn_bvc, *bss_bvc;
Harald Weltedf690e82020-12-12 15:58:28 +01001236 struct gbproxy_nse *nse;
Daniel Willmann76205712020-11-30 17:08:58 +01001237 unsigned int n_nses = 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001238 int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
Harald Welte8b4c7942020-12-05 10:14:49 +01001239 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001240
Harald Welte173a1822020-12-03 15:36:59 +01001241 if (TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001242 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001243 errctr = GBPROX_GLOB_CTR_OTHER_ERR;
Harald Weltedf690e82020-12-12 15:58:28 +01001244 sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
Harald Weltee5209642020-12-05 19:59:45 +01001245 if (!sgsn_bvc) {
Harald Weltedf690e82020-12-12 15:58:28 +01001246 LOGPNSE(sgsn_nse, LOGL_NOTICE, "Rx %s: unable to route: BVCI=%05u unknown\n",
Harald Weltee5209642020-12-05 19:59:45 +01001247 pdut_name, bvci);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001248 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001249 return -EINVAL;
1250 }
Harald Weltee5209642020-12-05 19:59:45 +01001251 LOGPBVC(sgsn_bvc, LOGL_INFO, "Rx %s: routing by BVCI\n", pdut_name);
1252 return gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Harald Welte173a1822020-12-03 15:36:59 +01001253 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {
Philipp Maierda3af942021-02-04 21:54:09 +01001254 struct gprs_ra_id raid;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001255 errctr = GBPROX_GLOB_CTR_INV_RAI;
Philipp Maierda3af942021-02-04 21:54:09 +01001256 gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
Harald Welte560bdb32020-12-04 22:24:47 +01001257 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001258 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001259 hash_for_each(nse->bvcs, j, bss_bvc, list) {
Philipp Maierda3af942021-02-04 21:54:09 +01001260 if (gsm48_ra_equal(&bss_bvc->raid, &raid)) {
Harald Weltee5209642020-12-05 19:59:45 +01001261 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (RAI match)\n",
1262 pdut_name);
1263 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001264 n_nses++;
1265 /* Only send it once to each NSE */
1266 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001267 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001268 }
1269 }
Harald Welte173a1822020-12-03 15:36:59 +01001270 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_LOCATION_AREA, 5)) {
Philipp Maierda3af942021-02-04 21:54:09 +01001271 struct gsm48_ra_id lac;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001272 errctr = GBPROX_GLOB_CTR_INV_LAI;
Harald Welte560bdb32020-12-04 22:24:47 +01001273 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001274 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001275 hash_for_each(nse->bvcs, j, bss_bvc, list) {
Philipp Maierda3af942021-02-04 21:54:09 +01001276 gsm48_encode_ra(&lac, &bss_bvc->raid);
1277 if (!memcmp(&lac, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
Harald Weltee5209642020-12-05 19:59:45 +01001278 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (LAI match)\n",
1279 pdut_name);
1280 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001281 n_nses++;
1282 /* Only send it once to each NSE */
1283 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001284 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001285 }
1286 }
Daniel Willmann5614e572021-01-18 18:38:27 +01001287 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1) || broadcast) {
Harald Welte560bdb32020-12-04 22:24:47 +01001288 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +01001289 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltee5209642020-12-05 19:59:45 +01001290 hash_for_each(nse->bvcs, j, bss_bvc, list) {
1291 LOGPNSE(nse, LOGL_INFO, "Rx %s:routing to NSE (broadcast)\n", pdut_name);
1292 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +01001293 n_nses++;
1294 /* Only send it once to each NSE */
1295 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +01001296 }
Harald Welte53ee2062020-11-24 11:31:13 +01001297 }
1298 } else {
Harald Weltedf690e82020-12-12 15:58:28 +01001299 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, missing IE\n");
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001300 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Harald Welte53ee2062020-11-24 11:31:13 +01001301 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001302
Daniel Willmann76205712020-11-30 17:08:58 +01001303 if (n_nses == 0) {
Harald Weltedf690e82020-12-12 15:58:28 +01001304 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, no destination found\n");
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001305 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, errctr));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001306 return -EINVAL;
1307 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +01001308 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001309}
1310
1311/* Receive an incoming BVC-RESET message from the SGSN */
Harald Weltee5209642020-12-05 19:59:45 +01001312static int rx_bvc_reset_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp,
1313 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001314{
Harald Weltee5209642020-12-05 19:59:45 +01001315 uint16_t ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
1316 struct gbproxy_bvc *from_bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001317
Harald Weltee5209642020-12-05 19:59:45 +01001318 LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", ptp_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001319
Harald Weltee5209642020-12-05 19:59:45 +01001320 if (ptp_bvci == 0) {
1321 from_bvc = gbproxy_bvc_by_bvci(nse, 0);
1322 OSMO_ASSERT(from_bvc);
1323 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
1324 } else {
1325 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
1326 if (!from_bvc) {
1327 LOGPNSE(nse, LOGL_ERROR, "Rx BVC-RESET BVCI=%05u: Cannot find BVC\n", ptp_bvci);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001328 rate_ctr_inc(rate_ctr_group_get_ctr(nse->cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001329 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKNOWN_BVCI, &ptp_bvci, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001330 }
Harald Weltee5209642020-12-05 19:59:45 +01001331 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
Daniel Willmanne50550e2020-11-26 18:19:21 +01001332 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001333
1334 return 0;
1335}
1336
Philipp Maier1c5766b2021-02-09 17:03:03 +01001337/* Receive an incoming RIM message from the SGSN-side NS-VC */
1338static int gbprox_rx_rim_from_sgsn(struct tlv_parsed *tp, struct gbproxy_nse *nse, struct msgb *msg, char *log_pfx,
1339 const char *pdut_name)
1340{
1341 struct gbproxy_sgsn *sgsn;
1342 struct gbproxy_cell *dest_cell;
1343 struct bssgp_rim_routing_info dest_ri;
1344 struct bssgp_rim_routing_info src_ri;
1345 int rc;
Philipp Maier4499cf42021-02-10 17:54:44 +01001346 char ri_src_str[64];
1347 char ri_dest_str[64];
Daniel Willmannf8cba652021-02-12 04:59:47 +01001348 uint16_t ns_bvci = msgb_bvci(msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001349
1350 /* TODO: Reply with STATUS if BSSGP didn't negotiate RIM feature, see also comments in
1351 gbprox_rx_rim_from_bss() */
1352
1353 rc = bssgp_parse_rim_ri(&dest_ri, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
1354 TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
1355 if (rc < 0) {
1356 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse destination RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001357 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001358 }
1359 rc = bssgp_parse_rim_ri(&src_ri, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
1360 TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
1361 if (rc < 0) {
1362 LOGP(DGPRS, LOGL_ERROR, "%s %s cannot parse source RIM routing info\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001363 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001364 }
1365
1366 /* Since gbproxy is 2G only we do not expect to get RIM messages that target non-GERAN cells. */
1367 if (dest_ri.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
1368 LOGP(DGPRS, LOGL_ERROR, "%s %s destination RIM routing info is not GERAN (%s)\n", log_pfx, pdut_name,
1369 bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001370 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001371 }
1372
1373 /* Lookup destination cell */
1374 dest_cell = gbproxy_cell_by_cellid(nse->cfg, &dest_ri.geran.raid, dest_ri.geran.cid);
1375 if (!dest_cell) {
1376 LOGP(DGPRS, LOGL_NOTICE, "%s %s cannot find cell for destination RIM routing info (%s)\n", log_pfx,
1377 pdut_name, bssgp_rim_ri_name(&dest_ri));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001378 return tx_status(nse, ns_bvci, BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
Philipp Maier1c5766b2021-02-09 17:03:03 +01001379 }
1380
1381 /* TODO: Check if the BVC of the destination cell actually did negotiate RIM support, see also comments
1382 * in gbprox_rx_rim_from_bss() */
1383 sgsn = gbproxy_sgsn_by_nsei(nse->cfg, nse->nsei);
1384 OSMO_ASSERT(sgsn);
1385
Philipp Maier4499cf42021-02-10 17:54:44 +01001386 LOGP(DLBSSGP, LOGL_DEBUG, "%s %s relaying from SGSN(%05u/%s) RIM-PDU: src=%s, dest=%s\n",
1387 log_pfx, pdut_name, sgsn->nse->nsei, sgsn->name,
1388 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &src_ri),
1389 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &dest_ri));
Philipp Maier1c5766b2021-02-09 17:03:03 +01001390
1391 return gbprox_relay2peer(msg, dest_cell->bss_bvc, 0);
1392}
1393
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001394/* Receive an incoming signalling message from the SGSN-side NS-VC */
Harald Weltedbef0aa2020-12-07 17:48:11 +01001395static 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 +02001396{
Harald Weltedbef0aa2020-12-07 17:48:11 +01001397 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001398 uint8_t pdu_type = bgph->pdu_type;
Harald Weltee5209642020-12-05 19:59:45 +01001399 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
1400 struct gbproxy_config *cfg = nse->cfg;
1401 struct gbproxy_bvc *sgsn_bvc;
Philipp Maier74882dc2021-02-04 16:31:46 +01001402 struct tlv_parsed tp[2];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001403 int data_len;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001404 uint16_t bvci;
Harald Welteec0f8012020-12-06 16:32:01 +01001405 char log_pfx[32];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001406 int rc = 0;
Harald Welted2fef952020-12-05 00:31:07 +01001407 int i;
Daniel Willmann5614e572021-01-18 18:38:27 +01001408 bool paging_bc = false;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001409
Harald Weltee5209642020-12-05 19:59:45 +01001410 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);
1411
1412 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welteec0f8012020-12-06 16:32:01 +01001413
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001414 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welteec0f8012020-12-06 16:32:01 +01001415 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001416 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001417 }
1418
Harald Welte278dd272020-12-06 13:35:24 +01001419 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Weltee5209642020-12-05 19:59:45 +01001420 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001421 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte278dd272020-12-06 13:35:24 +01001422 }
1423
1424 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_DL)) {
Harald Weltee5209642020-12-05 19:59:45 +01001425 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);
Daniel Willmannf8cba652021-02-12 04:59:47 +01001426 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001427 }
1428
Harald Weltedbef0aa2020-12-07 17:48:11 +01001429 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welteec0f8012020-12-06 16:32:01 +01001430
Philipp Maier74882dc2021-02-04 16:31:46 +01001431 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 +01001432 DGPRS, log_pfx);
1433 if (rc < 0) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001434 rc = tx_status_from_tlvp(nse, rc, msg);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001435 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_SGSN));
Harald Welteec0f8012020-12-06 16:32:01 +01001436 return rc;
1437 }
Harald Weltee5209642020-12-05 19:59:45 +01001438 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
Philipp Maier74882dc2021-02-04 16:31:46 +01001439 msgb_bcid(msg) = (void *)tp;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001440
1441 switch (pdu_type) {
1442 case BSSGP_PDUT_BVC_RESET:
Harald Weltee5209642020-12-05 19:59:45 +01001443 /* resolve or create ggbproxy_bvc + handle in BVC-FSM */
Philipp Maier74882dc2021-02-04 16:31:46 +01001444 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1445 rc = rx_bvc_reset_from_sgsn(nse, msg, &tp[0], ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001446 break;
1447 case BSSGP_PDUT_BVC_RESET_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001448 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001449 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1450 if (!sgsn_bvc)
1451 goto err_no_bvc;
1452 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
1453 break;
1454 case BSSGP_PDUT_BVC_BLOCK_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001455 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001456 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
Daniel Willmanndc763fd2021-09-24 16:45:38 +02001457 if (!sgsn_bvc) {
1458 /* Check if BVC was blocked before */
1459 sgsn_bvc = gbproxy_bvc_by_bvci_inactive(nse, bvci);
1460 if (!sgsn_bvc)
1461 goto err_no_bvc;
1462 }
Harald Weltee5209642020-12-05 19:59:45 +01001463 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK_ACK, msg);
1464 break;
1465 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
Philipp Maier74882dc2021-02-04 16:31:46 +01001466 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001467 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1468 if (!sgsn_bvc)
1469 goto err_no_bvc;
1470 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK_ACK, msg);
Daniel Willmann8489e7a2020-11-03 21:12:42 +01001471 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001472 case BSSGP_PDUT_FLUSH_LL:
1473 /* simple case: BVCI IE is mandatory */
Philipp Maier74882dc2021-02-04 16:31:46 +01001474 bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
Harald Weltee5209642020-12-05 19:59:45 +01001475 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1476 if (!sgsn_bvc)
1477 goto err_no_bvc;
1478 if (sgsn_bvc->cell && sgsn_bvc->cell->bss_bvc)
1479 rc = gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001480 break;
Daniel Willmann5614e572021-01-18 18:38:27 +01001481 case BSSGP_PDUT_DUMMY_PAGING_PS:
1482 /* Routing area is optional in dummy paging and we have nothing else to go by
1483 * so in case it is missing we need to broadcast the paging */
1484 paging_bc = true;
1485 /* fall through */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001486 case BSSGP_PDUT_PAGING_PS:
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001487 {
1488 /* Cache the IMSI<->NSE to route PAGING REJECT */
1489 struct osmo_mobile_identity mi;
Philipp Maier74882dc2021-02-04 16:31:46 +01001490 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1491 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001492 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
Daniel Willmann361d0b52021-07-09 17:44:30 +02001493 gbproxy_imsi_cache_update(nse, mi.imsi, CACHE_USAGE_PAGING);
Daniel Willmann8613c9d2021-01-17 13:40:38 +01001494 /* fall through */
1495 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001496 case BSSGP_PDUT_PAGING_CS:
1497 /* process the paging request (LAI/RAI lookup) */
Philipp Maier74882dc2021-02-04 16:31:46 +01001498 rc = gbprox_rx_paging(nse, msg, pdut_name, &tp[0], ns_bvci, paging_bc);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001499 break;
1500 case BSSGP_PDUT_STATUS:
Daniel Willmann885f4302021-09-30 16:58:46 +02001501 {
1502 struct gbproxy_nse *nse_peer;
1503 uint32_t tlli;
1504
1505 /* Check if the status needs to be terminated locally */
1506 uint8_t cause = *TLVP_VAL(&tp[0], BSSGP_IE_CAUSE);
1507
1508 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI || cause == BSSGP_CAUSE_BVCI_BLOCKED) {
1509 /* Log and handle locally, BVCI should be present for these causes */
1510 if (!TLVP_PRESENT(&tp[0], BSSGP_IE_BVCI)) {
1511 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s), but BVCI is missing\n", cause,
1512 bssgp_cause_str(cause));
1513 break;
1514 }
1515 uint16_t ptp_bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
1516 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s) for PtP-BVC %05u\n", cause,
1517 bssgp_cause_str(cause), ptp_bvci);
1518 /* FIXME: Remove/block the other BSS/SGSN BVCs if present? */
1519 break;
1520 }
1521
1522 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s)\n", cause,
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001523 bssgp_cause_str(cause));
Daniel Willmann885f4302021-09-30 16:58:46 +02001524
Daniel Willmann3d8f5992021-10-27 16:05:37 +02001525
1526 if (gbproxy_bvci_from_status_pdu(tp, &bvci, log_pfx) == 0 && bvci != 0) {
1527 struct gbproxy_cell *cell = gbproxy_cell_by_bvci(cfg, bvci);
1528
1529 if ((!cell || !cell->bss_bvc || !cell->bss_bvc->nse)) {
1530 LOGPNSE(nse, LOGL_ERROR, "Rx STATUS cause=0x%02x(%s), but can't find NSE for cell\n",
1531 cause, bssgp_cause_str(cause));
1532 break;
1533 }
1534
1535 return gbprox_relay2nse(msg, cell->bss_bvc->nse, 0);
1536 }
1537
Daniel Willmann885f4302021-09-30 16:58:46 +02001538 if (gbproxy_tlli_from_status_pdu(msg, tp, &tlli, log_pfx) == 0) {
1539 nse_peer = gbproxy_nse_by_tlli(cfg, tlli);
1540 if (nse_peer)
1541 return gbprox_relay2nse(msg, nse_peer, 0);
1542 }
1543
1544 LOGPNSE(nse, LOGL_ERROR, "Unable to handle STATUS cause=0x%02x(%s)\n", cause,
1545 bssgp_cause_str(cause));
1546
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001547 break;
Daniel Willmann885f4302021-09-30 16:58:46 +02001548 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001549 /* those only exist in the SGSN -> BSS direction */
1550 case BSSGP_PDUT_SUSPEND_ACK:
1551 case BSSGP_PDUT_SUSPEND_NACK:
1552 case BSSGP_PDUT_RESUME_ACK:
1553 case BSSGP_PDUT_RESUME_NACK:
Daniel Willmann77493b12020-12-29 21:13:31 +01001554 {
1555 struct gbproxy_nse *nse_peer;
Philipp Maier74882dc2021-02-04 16:31:46 +01001556 uint32_t tlli = osmo_load32be(TLVP_VAL(&tp[0], BSSGP_IE_TLLI));
Daniel Willmann77493b12020-12-29 21:13:31 +01001557
1558 nse_peer = gbproxy_nse_by_tlli(cfg, tlli);
1559 if (!nse_peer) {
1560 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);
1561 /* TODO: Counter */
Daniel Willmannf8cba652021-02-12 04:59:47 +01001562 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Daniel Willmann77493b12020-12-29 21:13:31 +01001563 }
1564 /* Delete the entry after we're done */
1565 gbproxy_tlli_cache_remove(cfg, tlli);
1566 LOGPNSE(nse_peer, LOGL_DEBUG, "Rx %s: forwarding\n", pdut_name);
1567 gbprox_relay2nse(msg, nse_peer, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001568 break;
Daniel Willmann77493b12020-12-29 21:13:31 +01001569 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001570 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
Harald Welte7479c4d2020-12-02 20:06:04 +01001571 case BSSGP_PDUT_OVERLOAD:
Harald Weltee5209642020-12-05 19:59:45 +01001572 LOGPNSE(nse, LOGL_DEBUG, "Rx %s: broadcasting\n", pdut_name);
Harald Welte560bdb32020-12-04 22:24:47 +01001573 /* broadcast to all BSS-side bvcs */
Harald Welted2fef952020-12-05 00:31:07 +01001574 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte7479c4d2020-12-02 20:06:04 +01001575 gbprox_relay2nse(msg, nse, 0);
1576 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001577 break;
Harald Weltee5209642020-12-05 19:59:45 +01001578 case BSSGP_PDUT_RAN_INFO:
1579 case BSSGP_PDUT_RAN_INFO_REQ:
1580 case BSSGP_PDUT_RAN_INFO_ACK:
1581 case BSSGP_PDUT_RAN_INFO_ERROR:
1582 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
Philipp Maier1c5766b2021-02-09 17:03:03 +01001583 rc = gbprox_rx_rim_from_sgsn(tp, nse, msg, log_pfx, pdut_name);
Pau Espin Pedrola4296342021-05-07 13:33:34 +02001584 break;
Daniel Willmannf024eeb2021-07-06 14:02:41 +02001585 case BSSGP_PDUT_MS_REGISTR_ENQ_RESP:
1586 {
1587 struct gbproxy_nse *nse_peer;
1588 struct osmo_mobile_identity mi;
1589 const uint8_t *mi_data = TLVP_VAL(&tp[0], BSSGP_IE_IMSI);
1590 uint8_t mi_len = TLVP_LEN(&tp[0], BSSGP_IE_IMSI);
1591 osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
1592 nse_peer = gbproxy_nse_by_imsi(cfg, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1593 if (!nse_peer) {
1594 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);
1595 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
1596 } else if (nse_peer->sgsn_facing) {
1597 LOGPNSE(nse, LOGL_ERROR, "Forwarding %s failed: IMSI cache contains SGSN NSE", pdut_name);
1598 return tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
1599 }
1600 gbproxy_imsi_cache_remove(cfg, mi.imsi, CACHE_USAGE_MS_REG_ENQ);
1601 gbprox_relay2nse(msg, nse_peer, ns_bvci);
1602 break;
1603 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001604 default:
Harald Weltee5209642020-12-05 19:59:45 +01001605 LOGPNSE(nse, LOGL_NOTICE, "Rx %s: Not supported\n", pdut_name);
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001606 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_PROTO_ERR_SGSN));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001607 rc = tx_status(nse, ns_bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001608 break;
1609 }
1610
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001611 return rc;
Harald Weltee5209642020-12-05 19:59:45 +01001612
Harald Welte560bdb32020-12-04 22:24:47 +01001613err_no_bvc:
Daniel Willmann723bb362021-09-28 18:51:47 +02001614 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find BVC %05u\n", pdut_name, bvci);
Daniel Willmannc4b913b2021-09-24 16:43:42 +02001615 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_INV_BVCI));
Daniel Willmannf8cba652021-02-12 04:59:47 +01001616 return tx_status(nse, ns_bvci, BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001617}
1618
Harald Weltee5209642020-12-05 19:59:45 +01001619
1620/***********************************************************************
1621 * libosmogb NS/BSSGP integration
1622 ***********************************************************************/
1623
Alexander Couzens951e1332020-09-22 13:21:46 +02001624int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001625{
1626 int rc;
Alexander Couzens951e1332020-09-22 13:21:46 +02001627 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
1628 struct gprs_ns2_inst *nsi = cfg->nsi;
1629 struct osmo_gprs_ns2_prim nsp = {};
1630
1631 nsp.bvci = msgb_bvci(msg);
1632 nsp.nsei = msgb_nsei(msg);
1633
Alexander Couzens55c36f92021-01-27 20:56:55 +01001634 osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
Alexander Couzens951e1332020-09-22 13:21:46 +02001635 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
1636
1637 return rc;
1638}
1639
1640/* Main input function for Gb proxy */
1641int gbprox_rcvmsg(void *ctx, struct msgb *msg)
1642{
Alexander Couzens951e1332020-09-22 13:21:46 +02001643 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Harald Weltee5209642020-12-05 19:59:45 +01001644 uint16_t ns_bvci = msgb_bvci(msg);
1645 uint16_t nsei = msgb_nsei(msg);
1646 struct gbproxy_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001647
Harald Weltee5209642020-12-05 19:59:45 +01001648 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_SGSN);
1649 if (nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001650 /* ensure minimum length to decode PDU type */
1651 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
1652 return tx_status(nse, ns_bvci, BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
1653
Harald Weltee5209642020-12-05 19:59:45 +01001654 if (ns_bvci == 0 || ns_bvci == 1)
1655 return gbprox_rx_sig_from_sgsn(nse, msg, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001656 else
Harald Weltee5209642020-12-05 19:59:45 +01001657 return gbprox_rx_ptp_from_sgsn(nse, msg, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001658 }
1659
Harald Weltee5209642020-12-05 19:59:45 +01001660 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_BSS);
1661 if (!nse) {
1662 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) not known -> allocating\n", nsei);
1663 nse = gbproxy_nse_alloc(cfg, nsei, false);
1664 }
1665 if (nse) {
Daniel Willmannf8cba652021-02-12 04:59:47 +01001666 /* ensure minimum length to decode PDU type */
1667 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
1668 return tx_status(nse, ns_bvci, BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
1669
Harald Weltee5209642020-12-05 19:59:45 +01001670 if (ns_bvci == 0 || ns_bvci == 1)
1671 return gbprox_rx_sig_from_bss(nse, msg, ns_bvci);
1672 else
1673 return gbprox_rx_ptp_from_bss(nse, msg, ns_bvci);
1674 }
1675
1676 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001677}
1678
Alexander Couzens951e1332020-09-22 13:21:46 +02001679/* TODO: What about handling:
Alexander Couzens55c36f92021-01-27 20:56:55 +01001680 * GPRS_NS2_AFF_CAUSE_VC_FAILURE,
1681 GPRS_NS2_AFF_CAUSE_VC_RECOVERY,
Alexander Couzens951e1332020-09-22 13:21:46 +02001682 osmocom own causes
Alexander Couzens55c36f92021-01-27 20:56:55 +01001683 GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED,
1684 GPRS_NS2_AFF_CAUSE_SNS_FAILURE,
Alexander Couzens951e1332020-09-22 13:21:46 +02001685 */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001686
Alexander Couzens951e1332020-09-22 13:21:46 +02001687void gprs_ns_prim_status_cb(struct gbproxy_config *cfg, struct osmo_gprs_ns2_prim *nsp)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001688{
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001689 int i;
Harald Welte560bdb32020-12-04 22:24:47 +01001690 struct gbproxy_bvc *bvc;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001691 struct gbproxy_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001692
Alexander Couzens951e1332020-09-22 13:21:46 +02001693 switch (nsp->u.status.cause) {
Alexander Couzens55c36f92021-01-27 20:56:55 +01001694 case GPRS_NS2_AFF_CAUSE_SNS_FAILURE:
1695 case GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED:
Alexander Couzens951e1332020-09-22 13:21:46 +02001696 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001697
Alexander Couzens55c36f92021-01-27 20:56:55 +01001698 case GPRS_NS2_AFF_CAUSE_RECOVERY:
Harald Welte9b367d22021-01-18 13:55:51 +01001699 LOGP(DGPRS, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);
Daniel Willmannf96cac52021-03-09 16:14:18 +01001700 nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_SGSN);
1701 if (nse) {
Daniel Willmann37518b32021-05-27 18:13:36 +02001702 nse->alive = true;
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001703 // Update the NSE max SDU len
Daniel Willmannf96cac52021-03-09 16:14:18 +01001704 nse->max_sdu_len = nsp->u.status.mtu;
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001705
Harald Weltee5209642020-12-05 19:59:45 +01001706 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001707 bvc = gbproxy_bvc_by_bvci(nse, 0);
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001708 if (bvc) {
Daniel Willmannf96cac52021-03-09 16:14:18 +01001709 bssgp_bvc_fsm_set_max_pdu_len(bvc->fi, nse->max_sdu_len);
Daniel Willmann3ea37932021-02-10 13:41:14 +01001710 osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
Daniel Willmann38b9c9a2021-03-09 15:54:44 +01001711 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001712 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001713 break;
Alexander Couzens55c36f92021-01-27 20:56:55 +01001714 case GPRS_NS2_AFF_CAUSE_FAILURE:
Daniel Willmannf96cac52021-03-09 16:14:18 +01001715 nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_BSS | NSE_F_SGSN);
1716 if (!nse) {
1717 LOGP(DGPRS, LOGL_ERROR, "Unknown NSE(%05d) became unavailable\n", nsp->nsei);
1718 break;
1719 }
Daniel Willmann37518b32021-05-27 18:13:36 +02001720
1721 nse->alive = false;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001722 if (nse->sgsn_facing) {
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001723 struct hlist_node *ntmp;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001724 /* SGSN */
1725 /* TODO: When to block all PtP towards bss? Only if all SGSN are down? */
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001726 hash_for_each_safe(nse->bvcs, i, ntmp, bvc, list) {
1727 if (bvc->bvci == 0)
1728 continue;
1729 gbproxy_bvc_free(bvc);
1730 }
Pau Espin Pedrol56438362021-06-04 18:03:44 +02001731 rate_ctr_inc(rate_ctr_group_get_ctr(cfg->ctrg, GBPROX_GLOB_CTR_RESTART_RESET_SGSN));
Alexander Couzens951e1332020-09-22 13:21:46 +02001732 } else {
Daniel Willmannf96cac52021-03-09 16:14:18 +01001733 /* BSS became unavailable
1734 * Block matching PtP-BVCs on SGSN-side */
1735 hash_for_each(nse->bvcs, i, bvc, list) {
1736 if (bvc->bvci == 0)
1737 continue;
1738 /* Get BVC for each SGSN and send block request */
1739 struct gbproxy_cell *cell = bvc->cell;
1740 for (int j = 0; j < GBPROXY_MAX_NR_SGSN; j++) {
1741 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[j];
1742 if (!sgsn_bvc)
1743 continue;
1744
1745 /* Block BVC, indicate BSS equipment failure */
1746 uint8_t cause = BSSGP_CAUSE_EQUIP_FAIL;
1747 osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
Daniel Willmanndc763fd2021-09-24 16:45:38 +02001748 sgsn_bvc->inactive = true;
Daniel Willmannf96cac52021-03-09 16:14:18 +01001749 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001750 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001751
Daniel Willmann1f3470f2021-03-11 09:53:42 +01001752 /* This frees the BVCs for us as well */
1753 gbproxy_nse_free(nse);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001754 }
Harald Welte9b367d22021-01-18 13:55:51 +01001755 LOGP(DGPRS, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);
Alexander Couzens951e1332020-09-22 13:21:46 +02001756 break;
1757 default:
Harald Welte9b367d22021-01-18 13:55:51 +01001758 LOGP(DGPRS, LOGL_NOTICE, "NS: Unknown NS-STATUS.ind cause=%s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001759 gprs_ns2_aff_cause_prim_str(nsp->u.status.cause));
Alexander Couzens951e1332020-09-22 13:21:46 +02001760 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001761 }
Alexander Couzens951e1332020-09-22 13:21:46 +02001762}
1763
Alexander Couzens951e1332020-09-22 13:21:46 +02001764/* called by the ns layer */
1765int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
1766{
1767 struct osmo_gprs_ns2_prim *nsp;
1768 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Daniel Willmann8f407b12020-12-02 19:33:50 +01001769 uintptr_t bvci;
Alexander Couzens951e1332020-09-22 13:21:46 +02001770 int rc = 0;
1771
1772 if (oph->sap != SAP_NS)
1773 return 0;
1774
1775 nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
1776
1777 if (oph->operation != PRIM_OP_INDICATION) {
Harald Welte9b367d22021-01-18 13:55:51 +01001778 LOGP(DGPRS, LOGL_NOTICE, "NS: Unexpected primitive operation %s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001779 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +02001780 return 0;
1781 }
1782
1783 switch (oph->primitive) {
Alexander Couzens55c36f92021-01-27 20:56:55 +01001784 case GPRS_NS2_PRIM_UNIT_DATA:
Daniel Willmann8f407b12020-12-02 19:33:50 +01001785
Alexander Couzens951e1332020-09-22 13:21:46 +02001786 /* hand the message into the BSSGP implementation */
1787 msgb_bssgph(oph->msg) = oph->msg->l3h;
1788 msgb_bvci(oph->msg) = nsp->bvci;
1789 msgb_nsei(oph->msg) = nsp->nsei;
Daniel Willmann8f407b12020-12-02 19:33:50 +01001790 bvci = nsp->bvci | BVC_LOG_CTX_FLAG;
Alexander Couzens951e1332020-09-22 13:21:46 +02001791
Daniel Willmann8f407b12020-12-02 19:33:50 +01001792 log_set_context(LOG_CTX_GB_BVC, (void *)bvci);
Alexander Couzens951e1332020-09-22 13:21:46 +02001793 rc = gbprox_rcvmsg(cfg, oph->msg);
Daniel Willmannb6550102020-11-04 17:32:56 +01001794 msgb_free(oph->msg);
Alexander Couzens951e1332020-09-22 13:21:46 +02001795 break;
Alexander Couzens55c36f92021-01-27 20:56:55 +01001796 case GPRS_NS2_PRIM_STATUS:
Alexander Couzens951e1332020-09-22 13:21:46 +02001797 gprs_ns_prim_status_cb(cfg, nsp);
1798 break;
1799 default:
Harald Welte9b367d22021-01-18 13:55:51 +01001800 LOGP(DGPRS, LOGL_NOTICE, "NS: Unknown prim %s %s from NS\n",
Harald Welte95cf9fb2020-11-30 10:55:22 +01001801 gprs_ns2_prim_str(oph->primitive),
1802 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +02001803 break;
1804 }
1805
1806 return rc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001807}
1808
1809void gbprox_reset(struct gbproxy_config *cfg)
1810{
Harald Welted2fef952020-12-05 00:31:07 +01001811 struct gbproxy_nse *nse;
1812 struct hlist_node *ntmp;
Harald Welte8b4c7942020-12-05 10:14:49 +01001813 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001814
Harald Welted2fef952020-12-05 00:31:07 +01001815 hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +01001816 struct gbproxy_bvc *bvc;
1817 struct hlist_node *tmp;
1818 hash_for_each_safe(nse->bvcs, j, tmp, bvc, list)
Harald Welte560bdb32020-12-04 22:24:47 +01001819 gbproxy_bvc_free(bvc);
Daniel Willmanne50550e2020-11-26 18:19:21 +01001820
1821 gbproxy_nse_free(nse);
1822 }
Harald Weltee5209642020-12-05 19:59:45 +01001823 /* FIXME: cells */
1824 /* FIXME: SGSN side BVCs (except signaling) */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001825
1826 rate_ctr_group_free(cfg->ctrg);
1827 gbproxy_init_config(cfg);
1828}
1829
Daniel Willmann77493b12020-12-29 21:13:31 +01001830static void tlli_cache_cleanup(void *data)
1831{
1832 struct gbproxy_config *cfg = data;
1833 gbproxy_tlli_cache_cleanup(cfg);
1834
1835 /* TODO: Disable timer when cache is empty */
1836 osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);
1837}
1838
Daniel Willmannc8a50092021-01-17 13:11:41 +01001839static void imsi_cache_cleanup(void *data)
1840{
1841 struct gbproxy_config *cfg = data;
1842 gbproxy_imsi_cache_cleanup(cfg);
1843
1844 /* TODO: Disable timer when cache is empty */
1845 osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0);
1846}
1847
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001848int gbproxy_init_config(struct gbproxy_config *cfg)
1849{
1850 struct timespec tp;
1851
Harald Welte209dc9f2020-12-12 19:02:16 +01001852 /* by default we advertise 100% of the BSS-side capacity to _each_ SGSN */
1853 cfg->pool.bvc_fc_ratio = 100;
Daniel Willmannee834af2020-12-14 16:22:39 +01001854 cfg->pool.null_nri_ranges = osmo_nri_ranges_alloc(cfg);
Daniel Willmann77493b12020-12-29 21:13:31 +01001855 /* TODO: Make configurable */
Daniel Willmannbd12f3f2021-01-13 18:16:04 +01001856 cfg->tlli_cache.timeout = 10;
Daniel Willmannc8a50092021-01-17 13:11:41 +01001857 cfg->imsi_cache.timeout = 10;
Daniel Willmannee834af2020-12-14 16:22:39 +01001858
Harald Welted2fef952020-12-05 00:31:07 +01001859 hash_init(cfg->bss_nses);
Daniel Willmann1e7be5d2020-12-21 18:08:21 +01001860 hash_init(cfg->sgsn_nses);
1861 hash_init(cfg->cells);
Daniel Willmann77493b12020-12-29 21:13:31 +01001862 hash_init(cfg->tlli_cache.entries);
Daniel Willmannee834af2020-12-14 16:22:39 +01001863 INIT_LLIST_HEAD(&cfg->sgsns);
1864
Daniel Willmann77493b12020-12-29 21:13:31 +01001865 osmo_timer_setup(&cfg->tlli_cache.timer, tlli_cache_cleanup, cfg);
1866 osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);
1867
Daniel Willmannc8a50092021-01-17 13:11:41 +01001868 /* We could also combine both timers */
1869 osmo_timer_setup(&cfg->imsi_cache.timer, imsi_cache_cleanup, cfg);
1870 osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0);
1871
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001872 cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
1873 if (!cfg->ctrg) {
1874 LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
1875 return -1;
1876 }
1877 osmo_clock_gettime(CLOCK_REALTIME, &tp);
Harald Weltec169de42020-12-07 13:12:13 +01001878 osmo_fsm_log_timeouts(true);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001879
1880 return 0;
Oliver Smith29532c22021-01-29 11:13:00 +01001881}