blob: 53aecdf04ba6a3490aa796849b10bf7e2bb5d489 [file] [log] [blame]
Harald Welte9f75c352010-04-30 20:26:32 +02001/* NS-over-IP proxy */
2
Harald Welte5687ae62020-12-05 19:59:45 +01003/* (C) 2010-2020 by Harald Welte <laforge@gnumonks.org>
Holger Hans Peter Freyther90267a92013-10-23 11:24:17 +02004 * (C) 2010-2013 by On-Waves
5 * (C) 2013 by Holger Hans Peter Freyther
Harald Welte9f75c352010-04-30 20:26:32 +02006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * 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
Harald Welte9f75c352010-04-30 20:26:32 +020011 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte9f75c352010-04-30 20:26:32 +020017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * 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/>.
Harald Welte9f75c352010-04-30 20:26:32 +020020 *
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>
Harald Welte7fc98222010-05-11 10:15:42 +020031#include <arpa/inet.h>
Jacob Erlbeck7c101d92014-06-06 18:49:23 +020032#include <time.h>
Harald Welte9f75c352010-04-30 20:26:32 +020033
Harald Welte78db2442020-12-05 00:31:07 +010034#include <osmocom/core/hashtable.h>
Daniel Willmanne8c8ec92020-12-02 19:33:50 +010035#include <osmocom/core/logging.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010036#include <osmocom/core/talloc.h>
37#include <osmocom/core/select.h>
Jacob Erlbeckbc555742013-10-18 14:34:55 +020038#include <osmocom/core/rate_ctr.h>
Jacob Erlbeck46caed82015-11-02 15:15:38 +010039#include <osmocom/core/stats.h>
Jacob Erlbeckbc555742013-10-18 14:34:55 +020040
Alexander Couzens82182d02020-09-22 13:21:46 +020041#include <osmocom/gprs/gprs_ns2.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080042#include <osmocom/gprs/gprs_bssgp.h>
Harald Welte9e917642020-12-12 19:02:16 +010043#include <osmocom/gprs/gprs_bssgp2.h>
Alexander Couzens82182d02020-09-22 13:21:46 +020044#include <osmocom/gprs/gprs_bssgp_bss.h>
Harald Welte5687ae62020-12-05 19:59:45 +010045#include <osmocom/gprs/bssgp_bvc_fsm.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080046
Jacob Erlbeck7c101d92014-06-06 18:49:23 +020047#include <osmocom/gsm/gsm_utils.h>
48
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020049#include <osmocom/sgsn/signal.h>
50#include <osmocom/sgsn/debug.h>
51#include <osmocom/sgsn/gprs_gb_parse.h>
52#include <osmocom/sgsn/gb_proxy.h>
Harald Welte9f75c352010-04-30 20:26:32 +020053
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020054#include <osmocom/sgsn/gprs_llc.h>
Harald Welte53373bc2016-04-20 17:11:43 +020055#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020056#include <osmocom/sgsn/gprs_utils.h>
Jacob Erlbeck67a44452014-05-19 10:14:58 +020057
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +010058extern void *tall_sgsn_ctx;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020059
Jacob Erlbeckbc555742013-10-18 14:34:55 +020060static const struct rate_ctr_desc global_ctr_description[] = {
61 { "inv-bvci", "Invalid BVC Identifier " },
Jacob Erlbeck8f503592014-06-02 10:49:00 +020062 { "inv-lai", "Invalid Location Area Identifier" },
63 { "inv-rai", "Invalid Routing Area Identifier " },
Jacob Erlbeckbc555742013-10-18 14:34:55 +020064 { "inv-nsei", "No BVC established for NSEI " },
Pau Espin Pedrol437e2092018-07-24 12:41:26 +020065 { "proto-err:bss", "BSSGP protocol error (BSS )" },
66 { "proto-err:sgsn", "BSSGP protocol error (SGSN)" },
67 { "not-supp:bss", "Feature not supported (BSS )" },
68 { "not-supp:sgsn", "Feature not supported (SGSN)" },
69 { "restart:sgsn", "Restarted RESET procedure (SGSN)" },
70 { "tx-err:sgsn", "NS Transmission error (SGSN)" },
Jacob Erlbeckbc555742013-10-18 14:34:55 +020071 { "error", "Other error " },
Jacob Erlbeck006c0382014-05-27 13:49:04 +020072 { "mod-peer-err", "Patch error: no peer " },
Jacob Erlbeckbc555742013-10-18 14:34:55 +020073};
74
75static const struct rate_ctr_group_desc global_ctrg_desc = {
Max8a01a802017-12-20 13:10:11 +010076 .group_name_prefix = "gbproxy:global",
Jacob Erlbeckbc555742013-10-18 14:34:55 +020077 .group_description = "GBProxy Global Statistics",
78 .num_ctr = ARRAY_SIZE(global_ctr_description),
79 .ctr_desc = global_ctr_description,
Jacob Erlbeck46caed82015-11-02 15:15:38 +010080 .class_id = OSMO_STATS_CLASS_GLOBAL,
Jacob Erlbeckbc555742013-10-18 14:34:55 +020081};
82
Harald Welte8cd74402020-12-04 22:24:47 +010083static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,
Daniel Willmann8bca8de2020-11-03 21:11:45 +010084 uint16_t ns_bvci);
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +020085
Harald Welte4bf53ef2020-12-05 17:50:23 +010086
Harald Welte052d8552020-12-06 16:32:01 +010087/* generate BVC-STATUS message with cause value derived from TLV-parser error */
88static int tx_status_from_tlvp(enum osmo_tlv_parser_error tlv_p_err, struct msgb *orig_msg)
89{
90 uint8_t bssgp_cause;
91 switch (tlv_p_err) {
92 case OSMO_TLVP_ERR_MAND_IE_MISSING:
93 bssgp_cause = BSSGP_CAUSE_MISSING_MAND_IE;
94 break;
95 default:
96 bssgp_cause = BSSGP_CAUSE_PROTO_ERR_UNSPEC;
97 }
98 return bssgp_tx_status(bssgp_cause, NULL, orig_msg);
99}
100
Harald Welte69619e32010-05-03 19:05:10 +0200101/* strip off the NS header */
102static void strip_ns_hdr(struct msgb *msg)
103{
104 int strip_len = msgb_bssgph(msg) - msg->data;
105 msgb_pull(msg, strip_len);
106}
107
Harald Welte5687ae62020-12-05 19:59:45 +0100108#if 0
Harald Welte8cd74402020-12-04 22:24:47 +0100109/* feed a message down the NS-VC associated with the specified bvc */
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +0200110static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
Jacob Erlbeckf4d60c82014-08-26 14:47:15 +0200111 uint16_t ns_bvci, uint16_t sgsn_nsei)
Harald Welte672f5c42010-05-03 18:54:58 +0200112{
Harald Welte39d0bb52010-05-12 18:10:25 +0000113 /* create a copy of the message so the old one can
114 * be free()d safely when we return from gbprox_rcvmsg() */
Alexander Couzens82182d02020-09-22 13:21:46 +0200115 struct gprs_ns2_inst *nsi = cfg->nsi;
116 struct osmo_gprs_ns2_prim nsp = {};
Pau Espin Pedrol816a67d2018-08-15 13:53:48 +0200117 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2sgsn");
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200118 int rc;
Harald Welte39d0bb52010-05-12 18:10:25 +0000119
Daniel Willmann103a7ec2020-12-02 16:08:02 +0100120 DEBUGP(DGPRS, "NSE(%05u/BSS)-BVC(%05u) proxying BTS->SGSN NSE(%05u/SGSN)\n",
Jacob Erlbeckf4d60c82014-08-26 14:47:15 +0200121 msgb_nsei(msg), ns_bvci, sgsn_nsei);
Harald Welte44c48302010-05-03 19:22:32 +0200122
Alexander Couzens82182d02020-09-22 13:21:46 +0200123 nsp.bvci = ns_bvci;
124 nsp.nsei = sgsn_nsei;
Harald Welte672f5c42010-05-03 18:54:58 +0200125
Harald Welte69619e32010-05-03 19:05:10 +0200126 strip_ns_hdr(msg);
Alexander Couzens82182d02020-09-22 13:21:46 +0200127 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA,
128 PRIM_OP_REQUEST, msg);
129 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200130 if (rc < 0)
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +0200131 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_TX_ERR_SGSN]);
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200132 return rc;
Harald Welte672f5c42010-05-03 18:54:58 +0200133}
Harald Welte5687ae62020-12-05 19:59:45 +0100134#endif
Harald Welte672f5c42010-05-03 18:54:58 +0200135
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100136/* feed a message down the NSE */
137static int gbprox_relay2nse(struct msgb *old_msg, struct gbproxy_nse *nse,
Daniel Willmann8bca8de2020-11-03 21:11:45 +0100138 uint16_t ns_bvci)
Harald Welte9f75c352010-04-30 20:26:32 +0200139{
Daniel Willmann447ad442020-11-26 18:19:21 +0100140 OSMO_ASSERT(nse);
141 OSMO_ASSERT(nse->cfg);
142
Harald Welte39d0bb52010-05-12 18:10:25 +0000143 /* create a copy of the message so the old one can
144 * be free()d safely when we return from gbprox_rcvmsg() */
Daniel Willmann447ad442020-11-26 18:19:21 +0100145 struct gprs_ns2_inst *nsi = nse->cfg->nsi;
Alexander Couzens82182d02020-09-22 13:21:46 +0200146 struct osmo_gprs_ns2_prim nsp = {};
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100147 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2nse");
Harald Welte2636e892020-11-18 12:01:46 +0100148 uint32_t tlli;
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200149 int rc;
Harald Welte39d0bb52010-05-12 18:10:25 +0000150
Daniel Willmann103a7ec2020-12-02 16:08:02 +0100151 DEBUGP(DGPRS, "NSE(%05u/SGSN)-BVC(%05u) proxying SGSN->BSS NSE(%05u/BSS)\n",
Daniel Willmann447ad442020-11-26 18:19:21 +0100152 msgb_nsei(msg), ns_bvci, nse->nsei);
Harald Welte44c48302010-05-03 19:22:32 +0200153
Alexander Couzens82182d02020-09-22 13:21:46 +0200154 nsp.bvci = ns_bvci;
Daniel Willmann447ad442020-11-26 18:19:21 +0100155 nsp.nsei = nse->nsei;
Harald Welte9f75c352010-04-30 20:26:32 +0200156
Harald Welte0ab535b2010-05-13 10:34:56 +0200157 /* Strip the old NS header, it will be replaced with a new one */
Harald Welte69619e32010-05-03 19:05:10 +0200158 strip_ns_hdr(msg);
159
Harald Welte2636e892020-11-18 12:01:46 +0100160 /* TS 48.018 Section 5.4.2: The link selector parameter is
161 * defined in 3GPP TS 48.016. At one side of the Gb interface,
162 * all BSSGP UNITDATA PDUs related to an MS shall be passed with
163 * the same LSP, e.g. the LSP contains the MS's TLLI, to the
164 * underlying network service. */
165 if (gprs_gb_parse_tlli(msgb_data(msg), msgb_length(msg), &tlli) == 1)
166 nsp.u.unitdata.link_selector = tlli;
167
Alexander Couzens82182d02020-09-22 13:21:46 +0200168 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA,
169 PRIM_OP_REQUEST, msg);
170 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100171 /* FIXME: We need a counter group for gbproxy_nse */
172 //if (rc < 0)
Harald Welte8cd74402020-12-04 22:24:47 +0100173 // rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_TX_ERR]);
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100174
175 return rc;
176}
177
Harald Welte8cd74402020-12-04 22:24:47 +0100178/* feed a message down the NS-VC associated with the specified bvc */
179static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100180 uint16_t ns_bvci)
181{
182 int rc;
Harald Welte8cd74402020-12-04 22:24:47 +0100183 struct gbproxy_nse *nse = bvc->nse;
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100184 OSMO_ASSERT(nse);
185
186 rc = gbprox_relay2nse(old_msg, nse, ns_bvci);
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200187 if (rc < 0)
Harald Welte8cd74402020-12-04 22:24:47 +0100188 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_TX_ERR]);
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200189
190 return rc;
Harald Welte9f75c352010-04-30 20:26:32 +0200191}
192
Harald Welteb1fd9022012-06-17 12:16:31 +0800193int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
194{
195 return 0;
196}
197
Harald Welte5687ae62020-12-05 19:59:45 +0100198
199/***********************************************************************
200 * PTP BVC handling
201 ***********************************************************************/
202
203/* route an uplink message on a PTP-BVC to a SGSN using the TLLI */
204static int gbprox_bss2sgsn_tlli(struct gbproxy_cell *cell, struct msgb *msg, uint32_t tlli,
205 bool sig_bvci)
206{
207 struct gbproxy_bvc *sgsn_bvc;
208 unsigned int i;
209
210 /* FIXME: derive NRI from TLLI */
211 /* FIXME: find the SGSN for that NRI */
212
213 /* HACK: we currently simply pick the first SGSN we find */
214 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
215 sgsn_bvc = cell->sgsn_bvc[i];
216 if (sgsn_bvc)
217 return gbprox_relay2peer(msg, sgsn_bvc, sig_bvci ? 0 : sgsn_bvc->bvci);
218 }
219 return 0;
220}
221
222static int gbprox_bss2sgsn_null_nri(struct gbproxy_cell *cell, struct msgb *msg)
223{
224 struct gbproxy_bvc *sgsn_bvc;
225 unsigned int i;
226
227 /* FIXME: find the SGSN for that NRI */
228
229 /* HACK: we currently simply pick the first SGSN we find */
230 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
231 sgsn_bvc = cell->sgsn_bvc[i];
232 if (sgsn_bvc)
233 return gbprox_relay2peer(msg, sgsn_bvc, sgsn_bvc->bvci);
234 }
235 return 0;
236}
237
238
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200239/* Receive an incoming PTP message from a BSS-side NS-VC */
Harald Welte5687ae62020-12-05 19:59:45 +0100240static int gbprox_rx_ptp_from_bss(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200241{
Harald Welted651edc2020-12-06 13:35:24 +0100242 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte5687ae62020-12-05 19:59:45 +0100243 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
244 struct gbproxy_bvc *bss_bvc;
245 struct tlv_parsed tp;
246 char log_pfx[32];
247 uint32_t tlli;
248 int rc;
249
250 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);
251
252 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200253
Daniel Willmannc4c1db92020-12-10 17:59:46 +0100254 if (ns_bvci == 0 || ns_bvci == 1) {
Harald Welte5687ae62020-12-05 19:59:45 +0100255 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not PTP\n", log_pfx, ns_bvci);
Harald Welted651edc2020-12-06 13:35:24 +0100256 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
257 }
258
259 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100260 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);
Harald Welted651edc2020-12-06 13:35:24 +0100261 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
262 }
263
264 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_UL)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100265 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);
Harald Welted651edc2020-12-06 13:35:24 +0100266 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
267 }
268
Harald Welte5687ae62020-12-05 19:59:45 +0100269 bss_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);
270 if (!bss_bvc) {
271 LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for PTP message, discarding\n",
272 log_pfx, pdut_name);
273 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);
Jacob Erlbeck058ae122014-10-10 09:07:04 +0200274 }
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200275
Harald Welte5687ae62020-12-05 19:59:45 +0100276 /* UL_UNITDATA has a different header than all other uplink PDUs */
277 if (bgph->pdu_type == BSSGP_PDUT_UL_UNITDATA) {
278 const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
279 if (msgb_bssgp_len(msg) < sizeof(*budh))
280 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
281 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, budh->data,
282 msgb_bssgp_len(msg) - sizeof(*budh), 0, 0, DGPRS, log_pfx);
283 /* populate TLLI from the fixed headser into the TLV-parsed array so later code
284 * doesn't have to worry where the TLLI came from */
285 tp.lv[BSSGP_IE_TLLI].len = 4;
286 tp.lv[BSSGP_IE_TLLI].val = (const uint8_t *) &budh->tlli;
287 } else {
288 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, bgph->data,
289 msgb_bssgp_len(msg) - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
290 }
291 if (rc < 0) {
292 rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
293 return tx_status_from_tlvp(rc, msg);
294 }
Harald Welte61ff2732020-12-08 21:43:22 +0100295 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
296 msgb_bcid(msg) = (void *)&tp;
Jacob Erlbeck43b8f9f2014-10-02 14:56:44 +0200297
Harald Welte5687ae62020-12-05 19:59:45 +0100298 switch (bgph->pdu_type) {
299 case BSSGP_PDUT_UL_UNITDATA:
300 case BSSGP_PDUT_RA_CAPA_UPDATE:
301 case BSSGP_PDUT_FLOW_CONTROL_MS:
302 case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
303 case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
304 case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
305 case BSSGP_PDUT_MODIFY_BSS_PFC_ACK:
306 case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
307 case BSSGP_PDUT_FLOW_CONTROL_PFC:
308 case BSSGP_PDUT_DELETE_BSS_PFC_REQ:
309 case BSSGP_PDUT_PS_HO_REQUIRED:
310 case BSSGP_PDUT_PS_HO_REQUEST_ACK:
311 case BSSGP_PDUT_PS_HO_REQUEST_NACK:
312 case BSSGP_PDUT_PS_HO_COMPLETE:
313 case BSSGP_PDUT_PS_HO_CANCEL:
314 /* We can route based on TLLI-NRI */
315 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
316 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, tlli, false);
317 break;
318 case BSSGP_PDUT_RADIO_STATUS:
319 if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
320 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
321 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, tlli, false);
322 } else if (TLVP_PRESENT(&tp, BSSGP_IE_TMSI)) {
323 /* we treat the TMSI like a TLLI and extract the NRI from it */
324 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TMSI));
325 rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, tlli, false);
326 } else if (TLVP_PRESENT(&tp, BSSGP_IE_IMSI)) {
327 rc = gbprox_bss2sgsn_null_nri(bss_bvc->cell, msg);
328 } else
329 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx RADIO-STATUS without any of the conditional IEs\n");
330 break;
331 case BSSGP_PDUT_DUMMY_PAGING_PS_RESP:
332 case BSSGP_PDUT_PAGING_PS_REJECT:
333 /* TODO: Implement via state tracking of PAGING-PS + DUMMY_PAGING_PS */
334 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);
335 break;
336 case BSSGP_PDUT_FLOW_CONTROL_BVC:
Harald Welte61ff2732020-12-08 21:43:22 +0100337 osmo_fsm_inst_dispatch(bss_bvc->fi, BSSGP_BVCFSM_E_RX_FC_BVC, msg);
Harald Welte5687ae62020-12-05 19:59:45 +0100338 break;
339 case BSSGP_PDUT_STATUS:
340 /* TODO: Implement by inspecting the contained PDU */
341 if (!TLVP_PRESENT(&tp, BSSGP_IE_PDU_IN_ERROR))
342 break;
343 LOGPBVC(bss_bvc, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);
344 break;
345 }
346
347 return 0;
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200348}
349
350/* Receive an incoming PTP message from a SGSN-side NS-VC */
Harald Welte5687ae62020-12-05 19:59:45 +0100351static int gbprox_rx_ptp_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200352{
Harald Welted651edc2020-12-06 13:35:24 +0100353 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte5687ae62020-12-05 19:59:45 +0100354 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
355 struct gbproxy_bvc *sgsn_bvc, *bss_bvc;
Harald Welte61ff2732020-12-08 21:43:22 +0100356 struct tlv_parsed tp;
Harald Welte5687ae62020-12-05 19:59:45 +0100357 char log_pfx[32];
Harald Welte61ff2732020-12-08 21:43:22 +0100358 int rc;
Harald Welte5687ae62020-12-05 19:59:45 +0100359
360 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);
361
362 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200363
Daniel Willmannc4c1db92020-12-10 17:59:46 +0100364 if (ns_bvci == 0 || ns_bvci == 1) {
Harald Welte5687ae62020-12-05 19:59:45 +0100365 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI is not PTP\n", log_pfx);
Harald Welted651edc2020-12-06 13:35:24 +0100366 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
367 }
368
369 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100370 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);
Harald Welted651edc2020-12-06 13:35:24 +0100371 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
372 }
373
374 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_DL)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100375 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);
Harald Welted651edc2020-12-06 13:35:24 +0100376 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
377 }
378
Harald Welte5687ae62020-12-05 19:59:45 +0100379 sgsn_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);
380 if (!sgsn_bvc) {
381 LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for for PTP message, discarding\n",
382 log_pfx, pdut_name);
383 rate_ctr_inc(&nse->cfg->ctrg-> ctr[GBPROX_GLOB_CTR_INV_BVCI]);
384 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200385 }
386
Harald Welte5687ae62020-12-05 19:59:45 +0100387 if (!bssgp_bvc_fsm_is_unblocked(sgsn_bvc->fi)) {
388 LOGPBVC(sgsn_bvc, LOGL_NOTICE, "Rx %s: Dropping on blocked BVC\n", pdut_name);
389 rate_ctr_inc(&sgsn_bvc->ctrg->ctr[GBPROX_PEER_CTR_DROPPED]);
Jacob Erlbeck17b42b82014-08-29 12:20:15 +0200390 return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &ns_bvci, msg);
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200391 }
Harald Welte61ff2732020-12-08 21:43:22 +0100392
393 /* DL_UNITDATA has a different header than all other uplink PDUs */
394 if (bgph->pdu_type == BSSGP_PDUT_DL_UNITDATA) {
395 const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
396 if (msgb_bssgp_len(msg) < sizeof(*budh))
397 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
398 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, budh->data,
399 msgb_bssgp_len(msg) - sizeof(*budh), 0, 0, DGPRS, log_pfx);
400 /* populate TLLI from the fixed headser into the TLV-parsed array so later code
401 * doesn't have to worry where the TLLI came from */
402 tp.lv[BSSGP_IE_TLLI].len = 4;
403 tp.lv[BSSGP_IE_TLLI].val = (const uint8_t *) &budh->tlli;
404 } else {
405 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, bgph->data,
406 msgb_bssgp_len(msg) - sizeof(*bgph), 0, 0, DGPRS, log_pfx);
407 }
408 if (rc < 0) {
409 rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
410 return tx_status_from_tlvp(rc, msg);
411 }
412 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
413 msgb_bcid(msg) = (void *)&tp;
414
Harald Welte5687ae62020-12-05 19:59:45 +0100415 OSMO_ASSERT(sgsn_bvc->cell);
416 bss_bvc = sgsn_bvc->cell->bss_bvc;
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200417
Harald Welte61ff2732020-12-08 21:43:22 +0100418 switch (bgph->pdu_type) {
419 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
420 return osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_FC_BVC_ACK, msg);
421 default:
422 return gbprox_relay2peer(msg, bss_bvc, bss_bvc->bvci);
423 }
424
Jacob Erlbeck46f1d6f2014-08-21 13:45:04 +0200425}
426
Harald Welte5687ae62020-12-05 19:59:45 +0100427/***********************************************************************
428 * BVC FSM call-backs
429 ***********************************************************************/
Harald Welteac44d6b2020-12-02 22:53:26 +0100430
Harald Welte5687ae62020-12-05 19:59:45 +0100431/* helper function to dispatch a FSM event to all SGSN-side BVC FSMs of a cell */
432static void dispatch_to_all_sgsn_bvc(struct gbproxy_cell *cell, uint32_t event, void *priv)
433{
434 unsigned int i;
435
436 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
437 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[i];
438 if (!sgsn_bvc)
439 continue;
440 osmo_fsm_inst_dispatch(sgsn_bvc->fi, event, priv);
441 }
442}
443
444/* BVC FSM informs us about a BSS-side reset of the signaling BVC */
445static void bss_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
446 uint16_t cell_id, uint8_t cause, void *priv)
447{
448 struct gbproxy_bvc *sig_bvc = priv;
449 struct gbproxy_nse *nse = sig_bvc->nse;
450 struct gbproxy_bvc *ptp_bvc;
451 unsigned int i;
452
453 /* BLOCK all SGSN-side PTP BVC within this NSE */
454 hash_for_each(nse->bvcs, i, ptp_bvc, list) {
455 if (ptp_bvc == sig_bvc)
456 continue;
457 OSMO_ASSERT(ptp_bvc->cell);
458
459 dispatch_to_all_sgsn_bvc(ptp_bvc->cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
Harald Weltefb7f8c52020-12-02 23:29:38 +0100460 }
Harald Welteac44d6b2020-12-02 22:53:26 +0100461
Harald Welte5687ae62020-12-05 19:59:45 +0100462 /* Delete all BSS-side PTP BVC within this NSE */
463 gbproxy_cleanup_bvcs(nse, 0);
464
465 /* TODO: we keep the "CELL" around for now, re-connecting it to
466 * any (later) new PTP-BVC for that BVCI. Not sure if that's the
467 * best idea ? */
468}
469
470/* forward declaration */
471static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops;
472
473static const struct bssgp_bvc_fsm_ops bss_sig_bvc_fsm_ops = {
474 .reset_notification = bss_sig_bvc_reset_notif,
475};
476
477/* BVC FSM informs us about a BSS-side reset of a PTP BVC */
478static void bss_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
479 uint16_t cell_id, uint8_t cause, void *priv)
480{
481 struct gbproxy_bvc *bvc = priv;
482 struct gbproxy_config *cfg = bvc->nse->cfg;
Harald Weltecab85882020-12-12 15:01:17 +0100483 struct gbproxy_nse *sgsn_nse;
Harald Welte5687ae62020-12-05 19:59:45 +0100484 unsigned int i;
485
486 OSMO_ASSERT(bvci != 0);
487
488 if (!bvc->cell) {
489 /* see if we have a CELL dangling around */
490 bvc->cell = gbproxy_cell_by_bvci(cfg, bvci);
491 if (bvc->cell) {
492 /* the CELL already exists. This means either it * was created before at an
493 * earlier PTP BVC-RESET, or that there are non-unique BVCIs and hence a
494 * malconfiguration */
495 if (bvc->cell->bss_bvc) {
496 LOGPBVC(bvc, LOGL_NOTICE, "Rx BVC-RESET via this NSE, but CELL already "
497 "has BVC on NSEI=%05u\n", bvc->cell->bss_bvc->nse->nsei);
498 LOGPBVC(bvc->cell->bss_bvc, LOGL_NOTICE, "Destroying due to conflicting "
499 "BVCI configuration (new NSEI=%05u)!\n", bvc->nse->nsei);
500 gbproxy_bvc_free(bvc->cell->bss_bvc);
501 }
502 bvc->cell->bss_bvc = bvc;
503 }
504 }
505
506 if (!bvc->cell) {
Harald Welte5687ae62020-12-05 19:59:45 +0100507 /* if we end up here, it means this is the first time we received a BVC-RESET
508 * for this BVC. We need to create the 'cell' data structure and the SGSN-side
509 * BVC counterparts */
510
511 bvc->cell = gbproxy_cell_alloc(cfg, bvci);
512 OSMO_ASSERT(bvc->cell);
Harald Welte4b4c9972020-12-12 14:22:32 +0100513 memcpy(bvc->cell->ra, bvc->ra, sizeof(bvc->cell->ra));
Harald Welte5687ae62020-12-05 19:59:45 +0100514
515 /* link us to the cell and vice-versa */
516 bvc->cell->bss_bvc = bvc;
Harald Weltecab85882020-12-12 15:01:17 +0100517 }
Harald Welte5687ae62020-12-05 19:59:45 +0100518
Harald Weltecab85882020-12-12 15:01:17 +0100519 /* allocate (any missing) SGSN-side BVCs within the cell, and reset them */
520 hash_for_each(cfg->sgsn_nses, i, sgsn_nse, list) {
521 struct gbproxy_bvc *sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
522 if (sgsn_bvc)
523 OSMO_ASSERT(sgsn_bvc->cell == bvc->cell || !sgsn_bvc->cell);
Harald Welte5687ae62020-12-05 19:59:45 +0100524
Harald Weltecab85882020-12-12 15:01:17 +0100525 if (!sgsn_bvc) {
526 sgsn_bvc = gbproxy_bvc_alloc(sgsn_nse, bvci);
527 OSMO_ASSERT(sgsn_bvc);
Harald Welte5687ae62020-12-05 19:59:45 +0100528
Harald Weltecab85882020-12-12 15:01:17 +0100529 sgsn_bvc->cell = bvc->cell;
530 memcpy(sgsn_bvc->ra, bvc->cell->ra, sizeof(sgsn_bvc->ra));
531 sgsn_bvc->fi = bssgp_bvc_fsm_alloc_ptp_bss(sgsn_bvc, cfg->nsi, sgsn_nse->nsei,
532 bvci, ra_id, cell_id);
533 OSMO_ASSERT(sgsn_bvc->fi);
534 bssgp_bvc_fsm_set_ops(sgsn_bvc->fi, &sgsn_ptp_bvc_fsm_ops, sgsn_bvc);
Harald Welte5687ae62020-12-05 19:59:45 +0100535
Harald Weltecab85882020-12-12 15:01:17 +0100536 gbproxy_cell_add_sgsn_bvc(bvc->cell, sgsn_bvc);
Harald Welte5687ae62020-12-05 19:59:45 +0100537 }
538 }
539
540 /* Trigger outbound BVC-RESET procedure toward each SGSN */
541 dispatch_to_all_sgsn_bvc(bvc->cell, BSSGP_BVCFSM_E_REQ_RESET, &cause);
542}
543
544/* BVC FSM informs us about a BSS-side FSM state change */
545static void bss_ptp_bvc_state_chg_notif(uint16_t nsei, uint16_t bvci, int old_state, int state, void *priv)
546{
547 struct gbproxy_bvc *bvc = priv;
548 struct gbproxy_cell *cell = bvc->cell;
549 uint8_t cause = bssgp_bvc_fsm_get_block_cause(bvc->fi);
550
551 /* we have just been created but due to callback ordering the cell is not associated */
552 if (!cell)
553 return;
554
555 switch (state) {
556 case BSSGP_BVCFSM_S_BLOCKED:
557 /* block the corresponding SGSN-side PTP BVCs */
558 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
559 break;
560 case BSSGP_BVCFSM_S_UNBLOCKED:
561 /* unblock the corresponding SGSN-side PTP BVCs */
562 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_UNBLOCK, NULL);
563 break;
564 }
565}
566
Harald Welte61ff2732020-12-08 21:43:22 +0100567/* BVC FSM informs us about BVC-FC PDU receive */
568static void bss_ptp_bvc_fc_bvc(uint16_t nsei, uint16_t bvci, const struct bssgp2_flow_ctrl *fc, void *priv)
569{
Harald Welte9e917642020-12-12 19:02:16 +0100570 struct bssgp2_flow_ctrl fc_reduced;
Harald Welte61ff2732020-12-08 21:43:22 +0100571 struct gbproxy_bvc *bss_bvc = priv;
Harald Welte9e917642020-12-12 19:02:16 +0100572 struct gbproxy_cell *cell;
573 struct gbproxy_config *cfg;
Harald Welte61ff2732020-12-08 21:43:22 +0100574
Harald Welte9e917642020-12-12 19:02:16 +0100575 OSMO_ASSERT(bss_bvc);
576 OSMO_ASSERT(fc);
577
578 cell = bss_bvc->cell;
Harald Welte61ff2732020-12-08 21:43:22 +0100579 if (!cell)
580 return;
581
Harald Welte9e917642020-12-12 19:02:16 +0100582 cfg = cell->cfg;
Harald Welte61ff2732020-12-08 21:43:22 +0100583
Harald Welte9e917642020-12-12 19:02:16 +0100584 /* reduce / scale according to configuration to make sure we only advertise a fraction
585 * of the capacity to each of the SGSNs in the pool */
586 fc_reduced = *fc;
587 fc_reduced.bucket_size_max = (fc->bucket_size_max * cfg->pool.bvc_fc_ratio) / 100;
588 fc_reduced.bucket_leak_rate = (fc->bucket_leak_rate * cfg->pool.bvc_fc_ratio) / 100;
589 /* we don't modify the per-MS related values as any single MS is only served by one SGSN */
590
591 dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_FC_BVC, (void *) &fc_reduced);
Harald Welte61ff2732020-12-08 21:43:22 +0100592}
593
Harald Welte5687ae62020-12-05 19:59:45 +0100594static const struct bssgp_bvc_fsm_ops bss_ptp_bvc_fsm_ops = {
595 .reset_notification = bss_ptp_bvc_reset_notif,
596 .state_chg_notification = bss_ptp_bvc_state_chg_notif,
Harald Welte61ff2732020-12-08 21:43:22 +0100597 .rx_fc_bvc = bss_ptp_bvc_fc_bvc,
Harald Welte5687ae62020-12-05 19:59:45 +0100598};
599
600/* BVC FSM informs us about a SGSN-side reset of a PTP BVC */
601static void sgsn_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
602 uint16_t cell_id, uint8_t cause, void *priv)
603{
604 struct gbproxy_bvc *bvc = priv;
605
606 if (!bvc->cell) {
607 LOGPBVC(bvc, LOGL_ERROR, "RESET of PTP BVC on SGSN side for which we have no BSS?\n");
608 return;
609 }
610
611 OSMO_ASSERT(bvc->cell->bss_bvc);
612
613 /* request reset of BSS-facing PTP-BVC */
614 osmo_fsm_inst_dispatch(bvc->cell->bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
615}
616
617static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops = {
618 .reset_notification = sgsn_ptp_bvc_reset_notif,
619};
620
621/* BVC FSM informs us about a SGSN-side reset of the signaling BVC */
622static void sgsn_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,
623 uint16_t cell_id, uint8_t cause, void *priv)
624{
625 struct gbproxy_bvc *bvc = priv;
626 struct gbproxy_config *cfg = bvc->nse->cfg;
627 struct gbproxy_nse *bss_nse;
628 unsigned int i;
629
630 /* delete all SGSN-side PTP BVC for this SGSN */
631 gbproxy_cleanup_bvcs(bvc->nse, 0);
632 /* FIXME: what to do about the cells? */
633 /* FIXME: do we really want to RESET all signaling BVC on the BSS and affect all other SGSN? */
634
635 /* we need to trigger generating a reset procedure towards each BSS side signaling BVC */
636 hash_for_each(cfg->bss_nses, i, bss_nse, list) {
637 struct gbproxy_bvc *bss_bvc = gbproxy_bvc_by_bvci(bss_nse, 0);
638 if (!bss_bvc) {
639 LOGPNSE(bss_nse, LOGL_ERROR, "Doesn't have BVC with BVCI=0 ?!?\n");
640 continue;
641 }
642 osmo_fsm_inst_dispatch(bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
643 }
644}
645
646const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops = {
647 .reset_notification = sgsn_sig_bvc_reset_notif,
648};
649
650/***********************************************************************
651 * Signaling BVC handling
652 ***********************************************************************/
653
654/* process a BVC-RESET message from the BSS side */
655static int rx_bvc_reset_from_bss(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp)
656{
657 struct gbproxy_bvc *from_bvc = NULL;
658 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
659 uint32_t features = 0; // FIXME: make configurable
660
661 LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", bvci);
662
Harald Welte1239cf42020-12-02 23:03:22 +0100663 if (bvci == 0) {
664 /* If we receive a BVC reset on the signalling endpoint, we
665 * don't want the SGSN to reset, as the signalling endpoint
666 * is common for all point-to-point BVCs (and thus all BTS) */
Harald Welte55253712020-12-02 23:06:37 +0100667
Harald Welte5687ae62020-12-05 19:59:45 +0100668 from_bvc = gbproxy_bvc_by_bvci(nse, 0);
Harald Welte8cd74402020-12-04 22:24:47 +0100669 if (!from_bvc) {
Harald Welte5687ae62020-12-05 19:59:45 +0100670 from_bvc = gbproxy_bvc_alloc(nse, 0);
671 OSMO_ASSERT(from_bvc);
672 from_bvc->fi = bssgp_bvc_fsm_alloc_sig_sgsn(from_bvc, nse->cfg->nsi, nse->nsei, features);
673 if (!from_bvc->fi) {
674 LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");
675 gbproxy_bvc_free(from_bvc);
676 return -ENOMEM;
Harald Welteac44d6b2020-12-02 22:53:26 +0100677 }
Harald Welte5687ae62020-12-05 19:59:45 +0100678 bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_sig_bvc_fsm_ops, from_bvc);
679 }
680 } else {
681 from_bvc = gbproxy_bvc_by_bvci(nse, bvci);
682 if (!from_bvc) {
Harald Welteac44d6b2020-12-02 22:53:26 +0100683 /* if a PTP-BVC is reset, and we don't know that
Harald Welte8cd74402020-12-04 22:24:47 +0100684 * PTP-BVCI yet, we should allocate a new bvc */
685 from_bvc = gbproxy_bvc_alloc(nse, bvci);
686 OSMO_ASSERT(from_bvc);
Harald Welte5687ae62020-12-05 19:59:45 +0100687 from_bvc->fi = bssgp_bvc_fsm_alloc_ptp_sgsn(from_bvc, nse->cfg->nsi,
688 nse->nsei, bvci);
689 if (!from_bvc->fi) {
690 LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");
691 gbproxy_bvc_free(from_bvc);
692 return -ENOMEM;
693 }
694 bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_ptp_bvc_fsm_ops, from_bvc);
Harald Welteac44d6b2020-12-02 22:53:26 +0100695 }
Harald Welte5687ae62020-12-05 19:59:45 +0100696#if 0
Harald Welteac44d6b2020-12-02 22:53:26 +0100697 /* Could have moved to a different NSE */
Harald Welte8cd74402020-12-04 22:24:47 +0100698 if (!check_bvc_nsei(from_bvc, nsei)) {
699 LOGPBVC(from_bvc, LOGL_NOTICE, "moving bvc to NSE(%05u)\n", nsei);
Harald Welteac44d6b2020-12-02 22:53:26 +0100700
Harald Welte5687ae62020-12-05 19:59:45 +0100701 struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei(cfg, nsei, false);
Harald Welteac44d6b2020-12-02 22:53:26 +0100702 if (!nse_new) {
703 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "
704 "BVCI=%05u\n", bvci, nsei);
705 bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, NULL, msg);
706 return 0;
707 }
708
Harald Welte8cd74402020-12-04 22:24:47 +0100709 /* Move bvc to different NSE */
710 gbproxy_bvc_move(from_bvc, nse_new);
Harald Welteac44d6b2020-12-02 22:53:26 +0100711 }
Harald Welte5687ae62020-12-05 19:59:45 +0100712#endif
713 /* FIXME: do we need this, if it happens within FSM? */
Harald Welte6c4c6f02020-12-03 15:36:59 +0100714 if (TLVP_PRES_LEN(tp, BSSGP_IE_CELL_ID, 8)) {
Harald Welteac44d6b2020-12-02 22:53:26 +0100715 struct gprs_ra_id raid;
716 /* We have a Cell Identifier present in this
717 * PDU, this means we can extend our local
718 * state information about this particular cell
719 * */
Harald Welte8cd74402020-12-04 22:24:47 +0100720 memcpy(from_bvc->ra, TLVP_VAL(tp, BSSGP_IE_CELL_ID), sizeof(from_bvc->ra));
721 gsm48_parse_ra(&raid, from_bvc->ra);
722 LOGPBVC(from_bvc, LOGL_INFO, "Cell ID %s\n", osmo_rai_name(&raid));
Harald Welteac44d6b2020-12-02 22:53:26 +0100723 }
Harald Welteac44d6b2020-12-02 22:53:26 +0100724 }
Harald Welte5687ae62020-12-05 19:59:45 +0100725 /* hand into FSM for further processing */
726 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
727 return 0;
Harald Welteac44d6b2020-12-02 22:53:26 +0100728}
729
Harald Welte9f75c352010-04-30 20:26:32 +0200730/* Receive an incoming signalling message from a BSS-side NS-VC */
Harald Welte5687ae62020-12-05 19:59:45 +0100731static int gbprox_rx_sig_from_bss(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Harald Welte9f75c352010-04-30 20:26:32 +0200732{
Harald Welteca3620a2010-05-03 16:30:59 +0200733 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte9f75c352010-04-30 20:26:32 +0200734 uint8_t pdu_type = bgph->pdu_type;
Harald Welte5687ae62020-12-05 19:59:45 +0100735 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
736 struct tlv_parsed tp;
Harald Welteca3620a2010-05-03 16:30:59 +0200737 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welte8cd74402020-12-04 22:24:47 +0100738 struct gbproxy_bvc *from_bvc = NULL;
Harald Welte052d8552020-12-06 16:32:01 +0100739 char log_pfx[32];
Harald Welte5687ae62020-12-05 19:59:45 +0100740 uint16_t ptp_bvci;
741 uint32_t tlli;
Jacob Erlbeck59300642014-09-08 09:04:01 +0200742 int rc;
Harald Welte9f75c352010-04-30 20:26:32 +0200743
Harald Welte5687ae62020-12-05 19:59:45 +0100744 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);
745
746 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welte052d8552020-12-06 16:32:01 +0100747
Harald Weltec471d3d2011-02-06 17:13:12 +0100748 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welte5687ae62020-12-05 19:59:45 +0100749 LOGP(DGPRS, LOGL_NOTICE, "%s %s BVCI=%05u is not signalling\n", log_pfx, pdut_name, ns_bvci);
Harald Welted651edc2020-12-06 13:35:24 +0100750 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte9f75c352010-04-30 20:26:32 +0200751 }
752
Harald Welted651edc2020-12-06 13:35:24 +0100753 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100754 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Harald Welted651edc2020-12-06 13:35:24 +0100755 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
756 }
757
758 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_UL)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100759 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);
Harald Welted651edc2020-12-06 13:35:24 +0100760 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte9f75c352010-04-30 20:26:32 +0200761 }
762
Harald Welte052d8552020-12-06 16:32:01 +0100763 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, pdu_type, bgph->data, data_len, 0, 0,
764 DGPRS, log_pfx);
765 if (rc < 0) {
Harald Welte5687ae62020-12-05 19:59:45 +0100766 rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
Harald Welte052d8552020-12-06 16:32:01 +0100767 return tx_status_from_tlvp(rc, msg);
768 }
Harald Welte5687ae62020-12-05 19:59:45 +0100769 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
770 msgb_bcid(msg) = (void *)&tp;
Harald Welte9f75c352010-04-30 20:26:32 +0200771
Harald Welte5687ae62020-12-05 19:59:45 +0100772 /* special case handling for some PDU types */
Harald Welte9f75c352010-04-30 20:26:32 +0200773 switch (pdu_type) {
Harald Welte5687ae62020-12-05 19:59:45 +0100774 case BSSGP_PDUT_BVC_RESET:
775 /* resolve or create gbproxy_bvc + handlei n BVC-FSM */
776 ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
777 return rx_bvc_reset_from_bss(nse, msg, &tp);
778 case BSSGP_PDUT_BVC_RESET_ACK:
779 ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
780 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
Harald Welte8cd74402020-12-04 22:24:47 +0100781 if (!from_bvc)
782 goto err_no_bvc;
Harald Welte5687ae62020-12-05 19:59:45 +0100783 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
784 case BSSGP_PDUT_BVC_BLOCK:
785 ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
786 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
787 if (!from_bvc)
788 goto err_no_bvc;
789 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK, msg);
790 case BSSGP_PDUT_BVC_UNBLOCK:
791 ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
792 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
793 if (!from_bvc)
794 goto err_no_bvc;
795 return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK, msg);
796 case BSSGP_PDUT_SUSPEND:
797 case BSSGP_PDUT_RESUME:
798 /* FIXME: Implement TLLI Cache. Every SUSPEND/RESUME we must
799 * take record of the TLLI->BVC mapping so we can map
800 * back from TLLI->BVC when the SUSPEND/RESUME-ACK
801 * arrives. Cache should have a timeout of 1-3 seconds
802 * and the ACK should explicitly delete entries. */
803#if 0
804 /* TODO: Validate the RAI for consistency with the RAI
805 * we expect for any of the BVC within this BSS side NSE */
806 memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), sizeof(from_bvc->ra));
Harald Welte8cd74402020-12-04 22:24:47 +0100807 gsm48_parse_ra(&raid, from_bvc->ra);
Harald Welte5687ae62020-12-05 19:59:45 +0100808#endif
Harald Welte9f75c352010-04-30 20:26:32 +0200809 break;
Harald Welte5687ae62020-12-05 19:59:45 +0100810 case BSSGP_PDUT_STATUS:
811 /* FIXME: inspect the erroneous PDU IE (if any) and check
812 * if we can extract a TLLI/RNI to route it to the correct SGSN */
813 break;
814 case BSSGP_PDUT_RAN_INFO:
815 case BSSGP_PDUT_RAN_INFO_REQ:
816 case BSSGP_PDUT_RAN_INFO_ACK:
817 case BSSGP_PDUT_RAN_INFO_ERROR:
818 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
819 /* FIXME: route based in RIM Routing IE */
820 rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
821 break;
822 case BSSGP_PDUT_LLC_DISCARD:
823 case BSSGP_PDUT_FLUSH_LL_ACK:
824 /* route based on BVCI + TLLI */
825 ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
826 tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
827 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
828 if (!from_bvc)
829 goto err_no_bvc;
830 gbprox_bss2sgsn_tlli(from_bvc->cell, msg, tlli, true);
831 break;
832 default:
833 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);
Harald Welte44c48302010-05-03 19:22:32 +0200834 break;
Harald Welte9f75c352010-04-30 20:26:32 +0200835 }
836
Harald Welte5687ae62020-12-05 19:59:45 +0100837 return rc;
Harald Welte8cd74402020-12-04 22:24:47 +0100838err_no_bvc:
Harald Welte5687ae62020-12-05 19:59:45 +0100839 LOGPNSE(nse, LOGL_ERROR, "Rx %s: cannot find BVC for BVCI=%05u\n", pdut_name, ptp_bvci);
840 rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_NSEI]);
Jacob Erlbeck17b42b82014-08-29 12:20:15 +0200841 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Harald Welte9f75c352010-04-30 20:26:32 +0200842}
843
844/* Receive paging request from SGSN, we need to relay to proper BSS */
Harald Welte1aa0ae92020-12-12 15:58:28 +0100845static int gbprox_rx_paging(struct gbproxy_nse *sgsn_nse, struct msgb *msg, const char *pdut_name,
Harald Welte5687ae62020-12-05 19:59:45 +0100846 struct tlv_parsed *tp, uint16_t ns_bvci)
Harald Welte9f75c352010-04-30 20:26:32 +0200847{
Harald Welte1aa0ae92020-12-12 15:58:28 +0100848 struct gbproxy_config *cfg = sgsn_nse->cfg;
Harald Welte5687ae62020-12-05 19:59:45 +0100849 struct gbproxy_bvc *sgsn_bvc, *bss_bvc;
Harald Welte1aa0ae92020-12-12 15:58:28 +0100850 struct gbproxy_nse *nse;
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100851 unsigned int n_nses = 0;
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200852 int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
Harald Welte993d3f42020-12-05 10:14:49 +0100853 int i, j;
Harald Welte9f75c352010-04-30 20:26:32 +0200854
Daniel Willmann447ad442020-11-26 18:19:21 +0100855 /* FIXME: Handle paging logic to only page each matching NSE */
856
Harald Welte6c4c6f02020-12-03 15:36:59 +0100857 if (TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Holger Hans Peter Freytherffd68562012-09-04 20:42:20 +0200858 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
Jacob Erlbeckbc555742013-10-18 14:34:55 +0200859 errctr = GBPROX_GLOB_CTR_OTHER_ERR;
Harald Welte1aa0ae92020-12-12 15:58:28 +0100860 sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
Harald Welte5687ae62020-12-05 19:59:45 +0100861 if (!sgsn_bvc) {
Harald Welte1aa0ae92020-12-12 15:58:28 +0100862 LOGPNSE(sgsn_nse, LOGL_NOTICE, "Rx %s: unable to route: BVCI=%05u unknown\n",
Harald Welte5687ae62020-12-05 19:59:45 +0100863 pdut_name, bvci);
Harald Welte3375fa42020-11-23 15:14:20 +0100864 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
865 return -EINVAL;
866 }
Harald Welte5687ae62020-12-05 19:59:45 +0100867 LOGPBVC(sgsn_bvc, LOGL_INFO, "Rx %s: routing by BVCI\n", pdut_name);
868 return gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Harald Welte6c4c6f02020-12-03 15:36:59 +0100869 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {
Jacob Erlbeck8f503592014-06-02 10:49:00 +0200870 errctr = GBPROX_GLOB_CTR_INV_RAI;
Harald Welte8cd74402020-12-04 22:24:47 +0100871 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welte78db2442020-12-05 00:31:07 +0100872 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte5687ae62020-12-05 19:59:45 +0100873 hash_for_each(nse->bvcs, j, bss_bvc, list) {
874 if (!memcmp(bss_bvc->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {
875 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (RAI match)\n",
876 pdut_name);
877 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100878 n_nses++;
879 /* Only send it once to each NSE */
880 break;
Daniel Willmann447ad442020-11-26 18:19:21 +0100881 }
Harald Welte3375fa42020-11-23 15:14:20 +0100882 }
883 }
Harald Welte6c4c6f02020-12-03 15:36:59 +0100884 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_LOCATION_AREA, 5)) {
Jacob Erlbeck8f503592014-06-02 10:49:00 +0200885 errctr = GBPROX_GLOB_CTR_INV_LAI;
Harald Welte8cd74402020-12-04 22:24:47 +0100886 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welte78db2442020-12-05 00:31:07 +0100887 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte5687ae62020-12-05 19:59:45 +0100888 hash_for_each(nse->bvcs, j, bss_bvc, list) {
889 if (!memcmp(bss_bvc->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
890 LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (LAI match)\n",
891 pdut_name);
892 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100893 n_nses++;
894 /* Only send it once to each NSE */
895 break;
Daniel Willmann447ad442020-11-26 18:19:21 +0100896 }
Harald Welte3375fa42020-11-23 15:14:20 +0100897 }
898 }
Harald Welte6c4c6f02020-12-03 15:36:59 +0100899 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1)) {
Harald Welte8cd74402020-12-04 22:24:47 +0100900 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welte78db2442020-12-05 00:31:07 +0100901 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte5687ae62020-12-05 19:59:45 +0100902 hash_for_each(nse->bvcs, j, bss_bvc, list) {
903 LOGPNSE(nse, LOGL_INFO, "Rx %s:routing to NSE (broadcast)\n", pdut_name);
904 gbprox_relay2peer(msg, bss_bvc, ns_bvci);
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100905 n_nses++;
906 /* Only send it once to each NSE */
907 break;
Daniel Willmann447ad442020-11-26 18:19:21 +0100908 }
Harald Welte8553f552020-11-24 11:31:13 +0100909 }
910 } else {
Harald Welte1aa0ae92020-12-12 15:58:28 +0100911 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, missing IE\n");
Harald Welte8553f552020-11-24 11:31:13 +0100912 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
913 }
Harald Welte4cf12e92010-05-13 14:14:56 +0200914
Daniel Willmann5937dfd2020-11-30 17:08:58 +0100915 if (n_nses == 0) {
Harald Welte1aa0ae92020-12-12 15:58:28 +0100916 LOGPNSE(sgsn_nse, LOGL_ERROR, "BSSGP PAGING: unable to route, no destination found\n");
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +0200917 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
Harald Welte9f75c352010-04-30 20:26:32 +0200918 return -EINVAL;
Harald Welte4cf12e92010-05-13 14:14:56 +0200919 }
Harald Welte3375fa42020-11-23 15:14:20 +0100920 return 0;
Harald Welte9f75c352010-04-30 20:26:32 +0200921}
922
Harald Welte0a4050c2010-05-11 10:01:17 +0200923/* Receive an incoming BVC-RESET message from the SGSN */
Harald Welte5687ae62020-12-05 19:59:45 +0100924static int rx_bvc_reset_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp,
925 uint16_t ns_bvci)
Harald Welte0a4050c2010-05-11 10:01:17 +0200926{
Harald Welte5687ae62020-12-05 19:59:45 +0100927 uint16_t ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
928 struct gbproxy_bvc *from_bvc;
Harald Welte0a4050c2010-05-11 10:01:17 +0200929
Harald Welte5687ae62020-12-05 19:59:45 +0100930 LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", ptp_bvci);
Harald Welte0a4050c2010-05-11 10:01:17 +0200931
Harald Welte5687ae62020-12-05 19:59:45 +0100932 if (ptp_bvci == 0) {
933 from_bvc = gbproxy_bvc_by_bvci(nse, 0);
934 OSMO_ASSERT(from_bvc);
935 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
936 } else {
937 from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);
938 if (!from_bvc) {
939 LOGPNSE(nse, LOGL_ERROR, "Rx BVC-RESET BVCI=%05u: Cannot find BVC\n", ptp_bvci);
940 rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);
941 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &ptp_bvci, msg);
Harald Welte0a4050c2010-05-11 10:01:17 +0200942 }
Harald Welte5687ae62020-12-05 19:59:45 +0100943 osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);
Daniel Willmann447ad442020-11-26 18:19:21 +0100944 }
Harald Welte0a4050c2010-05-11 10:01:17 +0200945
946 return 0;
947}
948
Harald Welte9f75c352010-04-30 20:26:32 +0200949/* Receive an incoming signalling message from the SGSN-side NS-VC */
Harald Weltebf698332020-12-07 17:48:11 +0100950static int gbprox_rx_sig_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)
Harald Welte9f75c352010-04-30 20:26:32 +0200951{
Harald Weltebf698332020-12-07 17:48:11 +0100952 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte9f75c352010-04-30 20:26:32 +0200953 uint8_t pdu_type = bgph->pdu_type;
Harald Welte5687ae62020-12-05 19:59:45 +0100954 const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);
955 struct gbproxy_config *cfg = nse->cfg;
956 struct gbproxy_bvc *sgsn_bvc;
957 struct tlv_parsed tp;
Jacob Erlbeck4b663ac2014-08-21 15:07:11 +0200958 int data_len;
Harald Welte9f75c352010-04-30 20:26:32 +0200959 uint16_t bvci;
Harald Welte052d8552020-12-06 16:32:01 +0100960 char log_pfx[32];
Harald Welte9f75c352010-04-30 20:26:32 +0200961 int rc = 0;
Jacob Erlbeck1e65b0e2014-08-29 13:32:17 +0200962 int cause;
Harald Welte78db2442020-12-05 00:31:07 +0100963 int i;
Harald Welte9f75c352010-04-30 20:26:32 +0200964
Harald Welte5687ae62020-12-05 19:59:45 +0100965 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);
966
967 LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);
Harald Welte052d8552020-12-06 16:32:01 +0100968
Harald Weltec471d3d2011-02-06 17:13:12 +0100969 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welte052d8552020-12-06 16:32:01 +0100970 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);
Harald Weltebf698332020-12-07 17:48:11 +0100971 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte9f75c352010-04-30 20:26:32 +0200972 }
973
Harald Welted651edc2020-12-06 13:35:24 +0100974 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100975 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);
Harald Weltebf698332020-12-07 17:48:11 +0100976 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welted651edc2020-12-06 13:35:24 +0100977 }
978
979 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_DL)) {
Harald Welte5687ae62020-12-05 19:59:45 +0100980 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);
Harald Weltebf698332020-12-07 17:48:11 +0100981 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte9f75c352010-04-30 20:26:32 +0200982 }
983
Harald Weltebf698332020-12-07 17:48:11 +0100984 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welte052d8552020-12-06 16:32:01 +0100985
986 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, pdu_type, bgph->data, data_len, 0, 0,
987 DGPRS, log_pfx);
988 if (rc < 0) {
989 rc = tx_status_from_tlvp(rc, msg);
Harald Welte052d8552020-12-06 16:32:01 +0100990 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
991 return rc;
992 }
Harald Welte5687ae62020-12-05 19:59:45 +0100993 /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */
994 msgb_bcid(msg) = (void *)&tp;
Harald Welte9f75c352010-04-30 20:26:32 +0200995
996 switch (pdu_type) {
Harald Welte0a4050c2010-05-11 10:01:17 +0200997 case BSSGP_PDUT_BVC_RESET:
Harald Welte5687ae62020-12-05 19:59:45 +0100998 /* resolve or create ggbproxy_bvc + handle in BVC-FSM */
999 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
1000 rc = rx_bvc_reset_from_sgsn(nse, msg, &tp, ns_bvci);
Harald Welte0a4050c2010-05-11 10:01:17 +02001001 break;
Harald Welte9f75c352010-04-30 20:26:32 +02001002 case BSSGP_PDUT_BVC_RESET_ACK:
Daniel Willmann15c9da22020-11-03 21:12:42 +01001003 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
Harald Welte5687ae62020-12-05 19:59:45 +01001004 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1005 if (!sgsn_bvc)
1006 goto err_no_bvc;
1007 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);
1008 break;
1009 case BSSGP_PDUT_BVC_BLOCK_ACK:
1010 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
1011 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1012 if (!sgsn_bvc)
1013 goto err_no_bvc;
1014 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK_ACK, msg);
1015 break;
1016 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
1017 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
1018 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1019 if (!sgsn_bvc)
1020 goto err_no_bvc;
1021 rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK_ACK, msg);
Daniel Willmann15c9da22020-11-03 21:12:42 +01001022 break;
Jacob Erlbeckc1c57d32014-08-28 13:20:39 +02001023 case BSSGP_PDUT_FLUSH_LL:
Harald Welte9f75c352010-04-30 20:26:32 +02001024 /* simple case: BVCI IE is mandatory */
Holger Hans Peter Freytherffd68562012-09-04 20:42:20 +02001025 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
Harald Welte5687ae62020-12-05 19:59:45 +01001026 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1027 if (!sgsn_bvc)
1028 goto err_no_bvc;
1029 if (sgsn_bvc->cell && sgsn_bvc->cell->bss_bvc)
1030 rc = gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Harald Welte9f75c352010-04-30 20:26:32 +02001031 break;
1032 case BSSGP_PDUT_PAGING_PS:
1033 case BSSGP_PDUT_PAGING_CS:
Jacob Erlbeck8f503592014-06-02 10:49:00 +02001034 /* process the paging request (LAI/RAI lookup) */
Harald Welte5687ae62020-12-05 19:59:45 +01001035 rc = gbprox_rx_paging(nse, msg, pdut_name, &tp, ns_bvci);
Harald Welte9f75c352010-04-30 20:26:32 +02001036 break;
1037 case BSSGP_PDUT_STATUS:
Harald Welte0a4050c2010-05-11 10:01:17 +02001038 /* Some exception has occurred */
Jacob Erlbeck1e65b0e2014-08-29 13:32:17 +02001039 cause = *TLVP_VAL(&tp, BSSGP_IE_CAUSE);
Harald Welte5687ae62020-12-05 19:59:45 +01001040 LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s) ", cause,
Jacob Erlbeck1e65b0e2014-08-29 13:32:17 +02001041 bssgp_cause_str(cause));
Harald Welte6c4c6f02020-12-03 15:36:59 +01001042 if (TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2)) {
Jacob Erlbeck1e65b0e2014-08-29 13:32:17 +02001043 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
Daniel Willmann103a7ec2020-12-02 16:08:02 +01001044 LOGPC(DGPRS, LOGL_NOTICE, "BVCI=%05u\n", bvci);
Harald Welte5687ae62020-12-05 19:59:45 +01001045 sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
1046 /* don't send STATUS in response to STATUS if !bvc */
1047 if (sgsn_bvc && sgsn_bvc->cell && sgsn_bvc->cell->bss_bvc)
1048 rc = gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);
Harald Welte0a4050c2010-05-11 10:01:17 +02001049 } else
1050 LOGPC(DGPRS, LOGL_NOTICE, "\n");
Harald Welte9f75c352010-04-30 20:26:32 +02001051 break;
1052 /* those only exist in the SGSN -> BSS direction */
1053 case BSSGP_PDUT_SUSPEND_ACK:
1054 case BSSGP_PDUT_SUSPEND_NACK:
1055 case BSSGP_PDUT_RESUME_ACK:
1056 case BSSGP_PDUT_RESUME_NACK:
Harald Welte5687ae62020-12-05 19:59:45 +01001057 /* FIXME: handle based on TLLI cache. The RA-ID is not a unique
1058 * criterion, so we have to rely on the TLLI->BVC state created
1059 * while processing the SUSPEND/RESUME in uplink */
1060 /* FIXME: route to SGSN baed on NRI derived from TLLI */
Harald Welte36f98d92011-02-06 13:09:29 +01001061 break;
Harald Welte9f75c352010-04-30 20:26:32 +02001062 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
Harald Weltec8d98ac2020-12-02 20:06:04 +01001063 case BSSGP_PDUT_OVERLOAD:
Harald Welte5687ae62020-12-05 19:59:45 +01001064 LOGPNSE(nse, LOGL_DEBUG, "Rx %s: broadcasting\n", pdut_name);
Harald Welte8cd74402020-12-04 22:24:47 +01001065 /* broadcast to all BSS-side bvcs */
Harald Welte78db2442020-12-05 00:31:07 +01001066 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Weltec8d98ac2020-12-02 20:06:04 +01001067 gbprox_relay2nse(msg, nse, 0);
1068 }
Harald Welte9f75c352010-04-30 20:26:32 +02001069 break;
Harald Welte5687ae62020-12-05 19:59:45 +01001070 case BSSGP_PDUT_RAN_INFO:
1071 case BSSGP_PDUT_RAN_INFO_REQ:
1072 case BSSGP_PDUT_RAN_INFO_ACK:
1073 case BSSGP_PDUT_RAN_INFO_ERROR:
1074 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
1075 /* FIXME: route based in RIM Routing IE */
Harald Weltebf698332020-12-07 17:48:11 +01001076 rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
Harald Welte5687ae62020-12-05 19:59:45 +01001077 break;
Harald Welte9f75c352010-04-30 20:26:32 +02001078 default:
Harald Welte5687ae62020-12-05 19:59:45 +01001079 LOGPNSE(nse, LOGL_NOTICE, "Rx %s: Not supported\n", pdut_name);
1080 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
Harald Weltebf698332020-12-07 17:48:11 +01001081 rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Harald Welte9f75c352010-04-30 20:26:32 +02001082 break;
1083 }
1084
1085 return rc;
Harald Welte5687ae62020-12-05 19:59:45 +01001086
Harald Welte8cd74402020-12-04 22:24:47 +01001087err_no_bvc:
Harald Welte5687ae62020-12-05 19:59:45 +01001088 LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find BVC\n", pdut_name);
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +02001089 rate_ctr_inc(&cfg->ctrg-> ctr[GBPROX_GLOB_CTR_INV_RAI]);
Harald Weltebf698332020-12-07 17:48:11 +01001090 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
Harald Welte9f75c352010-04-30 20:26:32 +02001091}
1092
Harald Welte5687ae62020-12-05 19:59:45 +01001093
1094/***********************************************************************
1095 * libosmogb NS/BSSGP integration
1096 ***********************************************************************/
1097
Alexander Couzens82182d02020-09-22 13:21:46 +02001098int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg)
Harald Welte9f75c352010-04-30 20:26:32 +02001099{
Harald Welte672f5c42010-05-03 18:54:58 +02001100 int rc;
Alexander Couzens82182d02020-09-22 13:21:46 +02001101 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
1102 struct gprs_ns2_inst *nsi = cfg->nsi;
1103 struct osmo_gprs_ns2_prim nsp = {};
1104
1105 nsp.bvci = msgb_bvci(msg);
1106 nsp.nsei = msgb_nsei(msg);
1107
1108 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA, PRIM_OP_REQUEST, msg);
1109 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
1110
1111 return rc;
1112}
1113
1114/* Main input function for Gb proxy */
1115int gbprox_rcvmsg(void *ctx, struct msgb *msg)
1116{
Alexander Couzens82182d02020-09-22 13:21:46 +02001117 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Harald Welte5687ae62020-12-05 19:59:45 +01001118 uint16_t ns_bvci = msgb_bvci(msg);
1119 uint16_t nsei = msgb_nsei(msg);
1120 struct gbproxy_nse *nse;
Harald Welte9f75c352010-04-30 20:26:32 +02001121
Harald Welted651edc2020-12-06 13:35:24 +01001122 /* ensure minimum length to decode PCU type */
1123 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
1124 return bssgp_tx_status(BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
1125
Harald Welte5687ae62020-12-05 19:59:45 +01001126 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_SGSN);
1127 if (nse) {
1128 if (ns_bvci == 0 || ns_bvci == 1)
1129 return gbprox_rx_sig_from_sgsn(nse, msg, ns_bvci);
Harald Welte9f75c352010-04-30 20:26:32 +02001130 else
Harald Welte5687ae62020-12-05 19:59:45 +01001131 return gbprox_rx_ptp_from_sgsn(nse, msg, ns_bvci);
Harald Welte9f75c352010-04-30 20:26:32 +02001132 }
1133
Harald Welte5687ae62020-12-05 19:59:45 +01001134 nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_BSS);
1135 if (!nse) {
1136 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) not known -> allocating\n", nsei);
1137 nse = gbproxy_nse_alloc(cfg, nsei, false);
1138 }
1139 if (nse) {
1140 if (ns_bvci == 0 || ns_bvci == 1)
1141 return gbprox_rx_sig_from_bss(nse, msg, ns_bvci);
1142 else
1143 return gbprox_rx_ptp_from_bss(nse, msg, ns_bvci);
1144 }
1145
1146 return 0;
Harald Welte9f75c352010-04-30 20:26:32 +02001147}
Harald Welte85801d02010-05-11 05:49:43 +02001148
Alexander Couzens82182d02020-09-22 13:21:46 +02001149/* TODO: What about handling:
1150 * NS_AFF_CAUSE_VC_FAILURE,
1151 NS_AFF_CAUSE_VC_RECOVERY,
1152 NS_AFF_CAUSE_FAILURE,
1153 NS_AFF_CAUSE_RECOVERY,
1154 osmocom own causes
1155 NS_AFF_CAUSE_SNS_CONFIGURED,
1156 NS_AFF_CAUSE_SNS_FAILURE,
1157 */
Harald Welte1ccbf442010-05-14 11:53:08 +00001158
Alexander Couzens82182d02020-09-22 13:21:46 +02001159void gprs_ns_prim_status_cb(struct gbproxy_config *cfg, struct osmo_gprs_ns2_prim *nsp)
Harald Weltec1c1dd22010-05-11 06:34:24 +02001160{
Harald Welte8cd74402020-12-04 22:24:47 +01001161 /* TODO: bss nsei available/unavailable bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, nsvc->nsei, bvc->bvci, 0);
Alexander Couzens82182d02020-09-22 13:21:46 +02001162 * TODO: sgsn nsei available/unavailable
1163 */
Harald Welte5687ae62020-12-05 19:59:45 +01001164
Harald Welte8cd74402020-12-04 22:24:47 +01001165 struct gbproxy_bvc *bvc;
Harald Welte5687ae62020-12-05 19:59:45 +01001166 struct gbproxy_nse *sgsn_nse;
Harald Weltec1c1dd22010-05-11 06:34:24 +02001167
Alexander Couzens82182d02020-09-22 13:21:46 +02001168 switch (nsp->u.status.cause) {
1169 case NS_AFF_CAUSE_SNS_FAILURE:
1170 case NS_AFF_CAUSE_SNS_CONFIGURED:
1171 break;
Harald Weltec1c1dd22010-05-11 06:34:24 +02001172
Alexander Couzens82182d02020-09-22 13:21:46 +02001173 case NS_AFF_CAUSE_RECOVERY:
1174 LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);
Harald Welte5687ae62020-12-05 19:59:45 +01001175 sgsn_nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_SGSN);
1176 if (sgsn_nse) {
1177 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
1178 bvc = gbproxy_bvc_by_bvci(sgsn_nse, 0);
1179 if (bvc)
1180 osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
Harald Welte5e106d72011-02-06 16:33:29 +01001181 }
Alexander Couzens82182d02020-09-22 13:21:46 +02001182 break;
1183 case NS_AFF_CAUSE_FAILURE:
Harald Welte5687ae62020-12-05 19:59:45 +01001184#if 0
Harald Welte4bf53ef2020-12-05 17:50:23 +01001185 if (gbproxy_is_sgsn_nsei(cfg, nsp->nsei)) {
Alexander Couzens82182d02020-09-22 13:21:46 +02001186 /* sgsn */
1187 /* TODO: BSVC: block all PtP towards bss */
1188 rate_ctr_inc(&cfg->ctrg->
1189 ctr[GBPROX_GLOB_CTR_RESTART_RESET_SGSN]);
1190 } else {
Daniel Willmann447ad442020-11-26 18:19:21 +01001191 /* bss became unavailable
1192 * TODO: Block all BVC belonging to that NSE */
Harald Welte8cd74402020-12-04 22:24:47 +01001193 bvc = gbproxy_bvc_by_nsei(cfg, nsp->nsei);
1194 if (!bvc) {
Alexander Couzens82182d02020-09-22 13:21:46 +02001195 /* TODO: use primitive name + status cause name */
Harald Welte8cd74402020-12-04 22:24:47 +01001196 LOGP(DGPRS, LOGL_NOTICE, "Received ns2 primitive %d for unknown bvc NSEI=%u\n",
Alexander Couzens82182d02020-09-22 13:21:46 +02001197 nsp->u.status.cause, nsp->nsei);
Harald Welte5e106d72011-02-06 16:33:29 +01001198 break;
1199 }
Alexander Couzens82182d02020-09-22 13:21:46 +02001200
Harald Welte8cd74402020-12-04 22:24:47 +01001201 if (!bvc->blocked)
Alexander Couzens82182d02020-09-22 13:21:46 +02001202 break;
Harald Welte5687ae62020-12-05 19:59:45 +01001203 hash_for_each(cfg->sgsn_nses, _sgsn, sgsn_nse, list) {
1204 bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, sgsn_nse->nsei, bvc->bvci, 0);
1205 }
Harald Weltec1c1dd22010-05-11 06:34:24 +02001206 }
Harald Welte5687ae62020-12-05 19:59:45 +01001207#endif
Alexander Couzens82182d02020-09-22 13:21:46 +02001208 LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);
1209 break;
1210 default:
Harald Welted97ff682020-11-30 10:55:22 +01001211 LOGP(DPCU, LOGL_NOTICE, "NS: Unknown NS-STATUS.ind cause=%s from NS\n",
1212 gprs_ns2_aff_cause_prim_str(nsp->u.status.cause));
Alexander Couzens82182d02020-09-22 13:21:46 +02001213 break;
Harald Weltec1c1dd22010-05-11 06:34:24 +02001214 }
Alexander Couzens82182d02020-09-22 13:21:46 +02001215}
1216
Alexander Couzens82182d02020-09-22 13:21:46 +02001217/* called by the ns layer */
1218int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
1219{
1220 struct osmo_gprs_ns2_prim *nsp;
1221 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Daniel Willmanne8c8ec92020-12-02 19:33:50 +01001222 uintptr_t bvci;
Alexander Couzens82182d02020-09-22 13:21:46 +02001223 int rc = 0;
1224
1225 if (oph->sap != SAP_NS)
1226 return 0;
1227
1228 nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
1229
1230 if (oph->operation != PRIM_OP_INDICATION) {
Harald Welted97ff682020-11-30 10:55:22 +01001231 LOGP(DPCU, LOGL_NOTICE, "NS: Unexpected primitive operation %s from NS\n",
1232 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens82182d02020-09-22 13:21:46 +02001233 return 0;
1234 }
1235
1236 switch (oph->primitive) {
1237 case PRIM_NS_UNIT_DATA:
Daniel Willmanne8c8ec92020-12-02 19:33:50 +01001238
Alexander Couzens82182d02020-09-22 13:21:46 +02001239 /* hand the message into the BSSGP implementation */
1240 msgb_bssgph(oph->msg) = oph->msg->l3h;
1241 msgb_bvci(oph->msg) = nsp->bvci;
1242 msgb_nsei(oph->msg) = nsp->nsei;
Daniel Willmanne8c8ec92020-12-02 19:33:50 +01001243 bvci = nsp->bvci | BVC_LOG_CTX_FLAG;
Alexander Couzens82182d02020-09-22 13:21:46 +02001244
Daniel Willmanne8c8ec92020-12-02 19:33:50 +01001245 log_set_context(LOG_CTX_GB_BVC, (void *)bvci);
Alexander Couzens82182d02020-09-22 13:21:46 +02001246 rc = gbprox_rcvmsg(cfg, oph->msg);
Daniel Willmann02f2c342020-11-04 17:32:56 +01001247 msgb_free(oph->msg);
Alexander Couzens82182d02020-09-22 13:21:46 +02001248 break;
1249 case PRIM_NS_STATUS:
1250 gprs_ns_prim_status_cb(cfg, nsp);
1251 break;
1252 default:
Harald Welted97ff682020-11-30 10:55:22 +01001253 LOGP(DPCU, LOGL_NOTICE, "NS: Unknown prim %s %s from NS\n",
1254 gprs_ns2_prim_str(oph->primitive),
1255 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens82182d02020-09-22 13:21:46 +02001256 break;
1257 }
1258
1259 return rc;
Harald Weltec1c1dd22010-05-11 06:34:24 +02001260}
1261
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +02001262void gbprox_reset(struct gbproxy_config *cfg)
Jacob Erlbeck72b401f2013-10-24 12:48:55 +02001263{
Harald Welte78db2442020-12-05 00:31:07 +01001264 struct gbproxy_nse *nse;
1265 struct hlist_node *ntmp;
Harald Welte993d3f42020-12-05 10:14:49 +01001266 int i, j;
Jacob Erlbeck72b401f2013-10-24 12:48:55 +02001267
Harald Welte78db2442020-12-05 00:31:07 +01001268 hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
Harald Welte993d3f42020-12-05 10:14:49 +01001269 struct gbproxy_bvc *bvc;
1270 struct hlist_node *tmp;
1271 hash_for_each_safe(nse->bvcs, j, tmp, bvc, list)
Harald Welte8cd74402020-12-04 22:24:47 +01001272 gbproxy_bvc_free(bvc);
Daniel Willmann447ad442020-11-26 18:19:21 +01001273
1274 gbproxy_nse_free(nse);
1275 }
Harald Welte5687ae62020-12-05 19:59:45 +01001276 /* FIXME: cells */
1277 /* FIXME: SGSN side BVCs (except signaling) */
Jacob Erlbeck72b401f2013-10-24 12:48:55 +02001278
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +02001279 rate_ctr_group_free(cfg->ctrg);
1280 gbproxy_init_config(cfg);
Jacob Erlbeck72b401f2013-10-24 12:48:55 +02001281}
1282
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +02001283int gbproxy_init_config(struct gbproxy_config *cfg)
Jacob Erlbeck4211d792013-10-24 12:48:23 +02001284{
Jacob Erlbeck0d376712014-08-11 19:12:24 +02001285 struct timespec tp;
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +02001286
Harald Welte9e917642020-12-12 19:02:16 +01001287 /* by default we advertise 100% of the BSS-side capacity to _each_ SGSN */
1288 cfg->pool.bvc_fc_ratio = 100;
Harald Welte78db2442020-12-05 00:31:07 +01001289 hash_init(cfg->bss_nses);
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +01001290 cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
Harald Welte26c14652017-07-12 00:25:51 +02001291 if (!cfg->ctrg) {
1292 LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
1293 return -1;
1294 }
Pau Espin Pedrol36abead2018-08-17 13:27:20 +02001295 osmo_clock_gettime(CLOCK_REALTIME, &tp);
Harald Weltea54ed462020-12-07 13:12:13 +01001296 osmo_fsm_log_timeouts(true);
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +02001297
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +02001298 return 0;
Jacob Erlbeck4211d792013-10-24 12:48:23 +02001299}