blob: ecb74c056c5306dc2c6a4c63af60d9ca46d848b0 [file] [log] [blame]
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +02001/* NS-over-IP proxy */
2
3/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4 * (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>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020036#include <osmocom/core/talloc.h>
37#include <osmocom/core/select.h>
38#include <osmocom/core/rate_ctr.h>
39#include <osmocom/core/stats.h>
40
Alexander Couzens951e1332020-09-22 13:21:46 +020041#include <osmocom/gprs/gprs_ns2.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020042#include <osmocom/gprs/gprs_bssgp.h>
Alexander Couzens951e1332020-09-22 13:21:46 +020043#include <osmocom/gprs/gprs_bssgp_bss.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020044
45#include <osmocom/gsm/gsm_utils.h>
46
47#include <osmocom/sgsn/signal.h>
48#include <osmocom/sgsn/debug.h>
49#include <osmocom/sgsn/gprs_gb_parse.h>
50#include <osmocom/sgsn/gb_proxy.h>
51
52#include <osmocom/sgsn/gprs_llc.h>
53#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
54#include <osmocom/sgsn/gprs_utils.h>
55
56extern void *tall_sgsn_ctx;
57
58static const struct rate_ctr_desc global_ctr_description[] = {
59 { "inv-bvci", "Invalid BVC Identifier " },
60 { "inv-lai", "Invalid Location Area Identifier" },
61 { "inv-rai", "Invalid Routing Area Identifier " },
62 { "inv-nsei", "No BVC established for NSEI " },
63 { "proto-err:bss", "BSSGP protocol error (BSS )" },
64 { "proto-err:sgsn", "BSSGP protocol error (SGSN)" },
65 { "not-supp:bss", "Feature not supported (BSS )" },
66 { "not-supp:sgsn", "Feature not supported (SGSN)" },
67 { "restart:sgsn", "Restarted RESET procedure (SGSN)" },
68 { "tx-err:sgsn", "NS Transmission error (SGSN)" },
69 { "error", "Other error " },
70 { "mod-peer-err", "Patch error: no peer " },
71};
72
73static const struct rate_ctr_group_desc global_ctrg_desc = {
74 .group_name_prefix = "gbproxy:global",
75 .group_description = "GBProxy Global Statistics",
76 .num_ctr = ARRAY_SIZE(global_ctr_description),
77 .ctr_desc = global_ctr_description,
78 .class_id = OSMO_STATS_CLASS_GLOBAL,
79};
80
Harald Welte560bdb32020-12-04 22:24:47 +010081static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,
Daniel Willmann35f7d332020-11-03 21:11:45 +010082 uint16_t ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020083static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
84 uint16_t ns_bvci, uint16_t sgsn_nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020085
Harald Weltea0f70732020-12-05 17:50:23 +010086
87static int gbproxy_is_sgsn_nsei(struct gbproxy_config *cfg, uint16_t nsei)
88{
89 return nsei == cfg->nsip_sgsn_nsei;
90}
91
Harald Welte560bdb32020-12-04 22:24:47 +010092static int check_bvc_nsei(struct gbproxy_bvc *bvc, uint16_t nsei)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020093{
Harald Welte560bdb32020-12-04 22:24:47 +010094 OSMO_ASSERT(bvc);
95 OSMO_ASSERT(bvc->nse);
Daniel Willmanne50550e2020-11-26 18:19:21 +010096
Harald Welte560bdb32020-12-04 22:24:47 +010097 if (bvc->nse->nsei != nsei) {
98 LOGPBVC(bvc, LOGL_NOTICE, "Peer entry doesn't match current NSEI "
Daniel Willmann5e595ca2020-12-02 13:54:21 +010099 "via NSE(%05u/BSS)\n", nsei);
Harald Welte560bdb32020-12-04 22:24:47 +0100100 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_INV_NSEI]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200101 return 0;
102 }
103
104 return 1;
105}
106
Harald Welteec0f8012020-12-06 16:32:01 +0100107/* generate BVC-STATUS message with cause value derived from TLV-parser error */
108static int tx_status_from_tlvp(enum osmo_tlv_parser_error tlv_p_err, struct msgb *orig_msg)
109{
110 uint8_t bssgp_cause;
111 switch (tlv_p_err) {
112 case OSMO_TLVP_ERR_MAND_IE_MISSING:
113 bssgp_cause = BSSGP_CAUSE_MISSING_MAND_IE;
114 break;
115 default:
116 bssgp_cause = BSSGP_CAUSE_PROTO_ERR_UNSPEC;
117 }
118 return bssgp_tx_status(bssgp_cause, NULL, orig_msg);
119}
120
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200121/* strip off the NS header */
122static void strip_ns_hdr(struct msgb *msg)
123{
124 int strip_len = msgb_bssgph(msg) - msg->data;
125 msgb_pull(msg, strip_len);
126}
127
Harald Welte560bdb32020-12-04 22:24:47 +0100128/* feed a message down the NS-VC associated with the specified bvc */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200129static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
130 uint16_t ns_bvci, uint16_t sgsn_nsei)
131{
132 /* create a copy of the message so the old one can
133 * be free()d safely when we return from gbprox_rcvmsg() */
Alexander Couzens951e1332020-09-22 13:21:46 +0200134 struct gprs_ns2_inst *nsi = cfg->nsi;
135 struct osmo_gprs_ns2_prim nsp = {};
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200136 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2sgsn");
137 int rc;
138
Daniel Willmann3696dce2020-12-02 16:08:02 +0100139 DEBUGP(DGPRS, "NSE(%05u/BSS)-BVC(%05u) proxying BTS->SGSN NSE(%05u/SGSN)\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200140 msgb_nsei(msg), ns_bvci, sgsn_nsei);
141
Alexander Couzens951e1332020-09-22 13:21:46 +0200142 nsp.bvci = ns_bvci;
143 nsp.nsei = sgsn_nsei;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200144
145 strip_ns_hdr(msg);
Alexander Couzens951e1332020-09-22 13:21:46 +0200146 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA,
147 PRIM_OP_REQUEST, msg);
148 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200149 if (rc < 0)
150 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_TX_ERR_SGSN]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200151 return rc;
152}
153
Daniel Willmann76205712020-11-30 17:08:58 +0100154/* feed a message down the NSE */
155static int gbprox_relay2nse(struct msgb *old_msg, struct gbproxy_nse *nse,
Daniel Willmann35f7d332020-11-03 21:11:45 +0100156 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200157{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100158 OSMO_ASSERT(nse);
159 OSMO_ASSERT(nse->cfg);
160
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200161 /* create a copy of the message so the old one can
162 * be free()d safely when we return from gbprox_rcvmsg() */
Daniel Willmanne50550e2020-11-26 18:19:21 +0100163 struct gprs_ns2_inst *nsi = nse->cfg->nsi;
Alexander Couzens951e1332020-09-22 13:21:46 +0200164 struct osmo_gprs_ns2_prim nsp = {};
Daniel Willmann76205712020-11-30 17:08:58 +0100165 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2nse");
Harald Weltefe059582020-11-18 12:01:46 +0100166 uint32_t tlli;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200167 int rc;
168
Daniel Willmann3696dce2020-12-02 16:08:02 +0100169 DEBUGP(DGPRS, "NSE(%05u/SGSN)-BVC(%05u) proxying SGSN->BSS NSE(%05u/BSS)\n",
Daniel Willmanne50550e2020-11-26 18:19:21 +0100170 msgb_nsei(msg), ns_bvci, nse->nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200171
Alexander Couzens951e1332020-09-22 13:21:46 +0200172 nsp.bvci = ns_bvci;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100173 nsp.nsei = nse->nsei;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200174
175 /* Strip the old NS header, it will be replaced with a new one */
176 strip_ns_hdr(msg);
177
Harald Weltefe059582020-11-18 12:01:46 +0100178 /* TS 48.018 Section 5.4.2: The link selector parameter is
179 * defined in 3GPP TS 48.016. At one side of the Gb interface,
180 * all BSSGP UNITDATA PDUs related to an MS shall be passed with
181 * the same LSP, e.g. the LSP contains the MS's TLLI, to the
182 * underlying network service. */
183 if (gprs_gb_parse_tlli(msgb_data(msg), msgb_length(msg), &tlli) == 1)
184 nsp.u.unitdata.link_selector = tlli;
185
Alexander Couzens951e1332020-09-22 13:21:46 +0200186 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA,
187 PRIM_OP_REQUEST, msg);
188 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
Daniel Willmann76205712020-11-30 17:08:58 +0100189 /* FIXME: We need a counter group for gbproxy_nse */
190 //if (rc < 0)
Harald Welte560bdb32020-12-04 22:24:47 +0100191 // rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_TX_ERR]);
Daniel Willmann76205712020-11-30 17:08:58 +0100192
193 return rc;
194}
195
Harald Welte560bdb32020-12-04 22:24:47 +0100196/* feed a message down the NS-VC associated with the specified bvc */
197static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,
Daniel Willmann76205712020-11-30 17:08:58 +0100198 uint16_t ns_bvci)
199{
200 int rc;
Harald Welte560bdb32020-12-04 22:24:47 +0100201 struct gbproxy_nse *nse = bvc->nse;
Daniel Willmann76205712020-11-30 17:08:58 +0100202 OSMO_ASSERT(nse);
203
204 rc = gbprox_relay2nse(old_msg, nse, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200205 if (rc < 0)
Harald Welte560bdb32020-12-04 22:24:47 +0100206 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_TX_ERR]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200207
208 return rc;
209}
210
Harald Welte560bdb32020-12-04 22:24:47 +0100211static int block_unblock_bvc(struct gbproxy_config *cfg, uint16_t ptp_bvci, uint8_t pdu_type)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200212{
Harald Welte560bdb32020-12-04 22:24:47 +0100213 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200214
Harald Welte560bdb32020-12-04 22:24:47 +0100215 bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);
216 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100217 LOGP(DGPRS, LOGL_ERROR, "BVC(%05u/??) Cannot find BSS\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200218 ptp_bvci);
219 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);
220 return -ENOENT;
221 }
222
223 switch (pdu_type) {
224 case BSSGP_PDUT_BVC_BLOCK_ACK:
Harald Welte560bdb32020-12-04 22:24:47 +0100225 bvc->blocked = true;
226 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_BLOCKED]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200227 break;
228 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
Harald Welte560bdb32020-12-04 22:24:47 +0100229 bvc->blocked = false;
230 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_UNBLOCKED]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200231 break;
232 default:
233 break;
234 }
235 return 0;
236}
237
Harald Welte560bdb32020-12-04 22:24:47 +0100238/* Send a message to a bvc identified by ptp_bvci but using ns_bvci
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200239 * in the NS hdr */
240static int gbprox_relay2bvci(struct gbproxy_config *cfg, struct msgb *msg, uint16_t ptp_bvci,
241 uint16_t ns_bvci)
242{
Harald Welte560bdb32020-12-04 22:24:47 +0100243 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200244
Harald Welte560bdb32020-12-04 22:24:47 +0100245 bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);
246 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100247 LOGP(DGPRS, LOGL_ERROR, "BVC(%05u/??) Cannot find BSS\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200248 ptp_bvci);
249 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);
250 return -ENOENT;
251 }
252
Harald Welte560bdb32020-12-04 22:24:47 +0100253 return gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200254}
255
256int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
257{
258 return 0;
259}
260
261/* Receive an incoming PTP message from a BSS-side NS-VC */
262static int gbprox_rx_ptp_from_bss(struct gbproxy_config *cfg,
263 struct msgb *msg, uint16_t nsei,
Alexander Couzens951e1332020-09-22 13:21:46 +0200264 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200265{
Harald Welte278dd272020-12-06 13:35:24 +0100266 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte560bdb32020-12-04 22:24:47 +0100267 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200268
Harald Welte278dd272020-12-06 13:35:24 +0100269 if (ns_bvci == 0 && ns_bvci == 1) {
270 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) BVCI=%05u is not PTP\n", nsei, ns_bvci);
271 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
272 }
273
274 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
275 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in PTP BVC\n",
276 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
277 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
278 }
279
280 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_UL)) {
281 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in uplink direction\n",
282 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
283 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
284 }
285
Harald Welte560bdb32020-12-04 22:24:47 +0100286 bvc = gbproxy_bvc_by_bvci(cfg, ns_bvci);
287 if (!bvc) {
288 LOGP(DGPRS, LOGL_NOTICE, "BVC(%05u/??) Didn't find bvc "
Daniel Willmann3696dce2020-12-02 16:08:02 +0100289 "for PTP message from NSE(%05u/BSS), "
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200290 "discarding message\n",
Alexander Couzens951e1332020-09-22 13:21:46 +0200291 ns_bvci, nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200292 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
293 &ns_bvci, msg);
294 }
295
Daniel Willmann65bfbaf2020-12-02 17:46:56 +0100296 /* TODO: Should we discard this message if the check fails */
Harald Welte560bdb32020-12-04 22:24:47 +0100297 check_bvc_nsei(bvc, nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200298
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200299 return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);
300}
301
302/* Receive an incoming PTP message from a SGSN-side NS-VC */
303static int gbprox_rx_ptp_from_sgsn(struct gbproxy_config *cfg,
304 struct msgb *msg, uint16_t nsei,
Alexander Couzens951e1332020-09-22 13:21:46 +0200305 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200306{
Harald Welte278dd272020-12-06 13:35:24 +0100307 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte560bdb32020-12-04 22:24:47 +0100308 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200309
Harald Welte278dd272020-12-06 13:35:24 +0100310 if (ns_bvci == 0 && ns_bvci == 1) {
311 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) BVCI=%05u is not PTP\n", nsei, ns_bvci);
312 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
313 }
314
315 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
316 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in PTP BVC\n",
317 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
318 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
319 }
320
321 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_DL)) {
322 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in downlink direction\n",
323 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
324 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
325 }
326
Harald Welte560bdb32020-12-04 22:24:47 +0100327 bvc = gbproxy_bvc_by_bvci(cfg, ns_bvci);
Harald Welte560bdb32020-12-04 22:24:47 +0100328 if (!bvc) {
329 LOGP(DGPRS, LOGL_INFO, "BVC(%05u/??) Didn't find bvc for "
Daniel Willmann3696dce2020-12-02 16:08:02 +0100330 "for message from NSE(%05u/SGSN)\n",
Alexander Couzens951e1332020-09-22 13:21:46 +0200331 ns_bvci, nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200332 rate_ctr_inc(&cfg->ctrg->
333 ctr[GBPROX_GLOB_CTR_INV_BVCI]);
334 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
335 &ns_bvci, msg);
336 }
337
Harald Welte560bdb32020-12-04 22:24:47 +0100338 if (bvc->blocked) {
339 LOGPBVC(bvc, LOGL_NOTICE, "Dropping PDU for "
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100340 "blocked BVC via NSE(%05u/SGSN)\n", nsei);
Harald Welte560bdb32020-12-04 22:24:47 +0100341 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_DROPPED]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200342 return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &ns_bvci, msg);
343 }
344
Harald Welte560bdb32020-12-04 22:24:47 +0100345 return gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200346}
347
Harald Welte7df1e5a2020-12-02 22:53:26 +0100348/* process a BVC-RESET message from the BSS side */
349static int gbprox_rx_bvc_reset_from_bss(struct gbproxy_config *cfg, struct msgb *msg,
Harald Welte7a0c9dd2020-12-05 11:18:23 +0100350 uint16_t nsei, struct tlv_parsed *tp)
Harald Welte7df1e5a2020-12-02 22:53:26 +0100351{
Harald Welte560bdb32020-12-04 22:24:47 +0100352 struct gbproxy_bvc *from_bvc = NULL;
Harald Welte314647b2020-12-02 23:03:22 +0100353 uint16_t bvci;
Harald Welte7df1e5a2020-12-02 22:53:26 +0100354
Harald Welte173a1822020-12-03 15:36:59 +0100355 if (!TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2) || !TLVP_PRES_LEN(tp, BSSGP_IE_CAUSE, 1)) {
Harald Weltef9e149b2020-12-02 23:29:38 +0100356 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
357 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
358 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100359
Harald Welte314647b2020-12-02 23:03:22 +0100360 bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
361 LOGP(DGPRS, LOGL_INFO, "NSE(%05u) Rx BVC RESET (BVCI=%05u)\n", nsei, bvci);
362 if (bvci == 0) {
363 /* If we receive a BVC reset on the signalling endpoint, we
364 * don't want the SGSN to reset, as the signalling endpoint
365 * is common for all point-to-point BVCs (and thus all BTS) */
Harald Welte324f0652020-12-02 23:06:37 +0100366
Harald Welte560bdb32020-12-04 22:24:47 +0100367 /* Ensure the NSE bvc is there and clear all PtP BVCs */
Harald Welte324f0652020-12-02 23:06:37 +0100368 struct gbproxy_nse *nse = gbproxy_nse_by_nsei_or_new(cfg, nsei);
Harald Welte314647b2020-12-02 23:03:22 +0100369 if (!nse) {
370 LOGP(DGPRS, LOGL_ERROR, "Could not create NSE(%05u)\n", nsei);
371 bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, 0, msg);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100372 return 0;
373 }
Harald Welte314647b2020-12-02 23:03:22 +0100374
Harald Welte560bdb32020-12-04 22:24:47 +0100375 gbproxy_cleanup_bvcs(cfg, nsei, 0);
Harald Welte314647b2020-12-02 23:03:22 +0100376
377 /* FIXME: only do this if SGSN is alive! */
Harald Welte324f0652020-12-02 23:06:37 +0100378 LOGPNSE(nse, LOGL_INFO, "Tx fake BVC RESET ACK of BVCI=0\n");
Harald Welte314647b2020-12-02 23:03:22 +0100379 bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsei, 0, 0);
380 return 0;
381 } else {
Harald Welte560bdb32020-12-04 22:24:47 +0100382 from_bvc = gbproxy_bvc_by_bvci(cfg, bvci);
383 if (!from_bvc) {
Harald Welte7df1e5a2020-12-02 22:53:26 +0100384 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(cfg, nsei);
385 if (!nse) {
386 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "
387 "BVCI=%05u\n", nsei, bvci);
388 bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, NULL, msg);
389 return 0;
390 }
391 /* if a PTP-BVC is reset, and we don't know that
Harald Welte560bdb32020-12-04 22:24:47 +0100392 * PTP-BVCI yet, we should allocate a new bvc */
393 from_bvc = gbproxy_bvc_alloc(nse, bvci);
394 OSMO_ASSERT(from_bvc);
395 LOGPBVC(from_bvc, LOGL_INFO, "Allocated new bvc\n");
Harald Welte7df1e5a2020-12-02 22:53:26 +0100396 }
397
398 /* Could have moved to a different NSE */
Harald Welte560bdb32020-12-04 22:24:47 +0100399 if (!check_bvc_nsei(from_bvc, nsei)) {
400 LOGPBVC(from_bvc, LOGL_NOTICE, "moving bvc to NSE(%05u)\n", nsei);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100401
402 struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei(cfg, nsei);
403 if (!nse_new) {
404 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "
405 "BVCI=%05u\n", bvci, nsei);
406 bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, NULL, msg);
407 return 0;
408 }
409
Harald Welte560bdb32020-12-04 22:24:47 +0100410 /* Move bvc to different NSE */
411 gbproxy_bvc_move(from_bvc, nse_new);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100412 }
413
Harald Welte173a1822020-12-03 15:36:59 +0100414 if (TLVP_PRES_LEN(tp, BSSGP_IE_CELL_ID, 8)) {
Harald Welte7df1e5a2020-12-02 22:53:26 +0100415 struct gprs_ra_id raid;
416 /* We have a Cell Identifier present in this
417 * PDU, this means we can extend our local
418 * state information about this particular cell
419 * */
Harald Welte560bdb32020-12-04 22:24:47 +0100420 memcpy(from_bvc->ra, TLVP_VAL(tp, BSSGP_IE_CELL_ID), sizeof(from_bvc->ra));
421 gsm48_parse_ra(&raid, from_bvc->ra);
422 LOGPBVC(from_bvc, LOGL_INFO, "Cell ID %s\n", osmo_rai_name(&raid));
Harald Welte7df1e5a2020-12-02 22:53:26 +0100423 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100424 }
425 /* continue processing / relaying to SGSN[s] */
426 return 1;
427}
428
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200429/* Receive an incoming signalling message from a BSS-side NS-VC */
430static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg,
431 struct msgb *msg, uint16_t nsei,
432 uint16_t ns_bvci)
433{
434 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
435 struct tlv_parsed tp;
436 uint8_t pdu_type = bgph->pdu_type;
437 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welte560bdb32020-12-04 22:24:47 +0100438 struct gbproxy_bvc *from_bvc = NULL;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200439 struct gprs_ra_id raid;
Harald Welteec0f8012020-12-06 16:32:01 +0100440 char log_pfx[32];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200441 int rc;
442
Harald Welteec0f8012020-12-06 16:32:01 +0100443 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)", nsei);
444
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200445 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welteec0f8012020-12-06 16:32:01 +0100446 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);
Harald Welte278dd272020-12-06 13:35:24 +0100447 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200448 }
449
Harald Welte278dd272020-12-06 13:35:24 +0100450 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Welteec0f8012020-12-06 16:32:01 +0100451 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx,
452 osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
Harald Welte278dd272020-12-06 13:35:24 +0100453 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
454 }
455
456 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_UL)) {
Harald Welteec0f8012020-12-06 16:32:01 +0100457 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx,
458 osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
Harald Welte278dd272020-12-06 13:35:24 +0100459 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200460 }
461
Harald Welteec0f8012020-12-06 16:32:01 +0100462 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, pdu_type, bgph->data, data_len, 0, 0,
463 DGPRS, log_pfx);
464 if (rc < 0) {
465 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
466 return tx_status_from_tlvp(rc, msg);
467 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200468
469 switch (pdu_type) {
470 case BSSGP_PDUT_SUSPEND:
471 case BSSGP_PDUT_RESUME:
472 /* We implement RAI snooping during SUSPEND/RESUME, since it
Harald Welte560bdb32020-12-04 22:24:47 +0100473 * establishes a relationsip between BVCI/bvc and the routeing
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200474 * area identification. The snooped information is then used
475 * for routing the {SUSPEND,RESUME}_[N]ACK back to the correct
476 * BSSGP */
Harald Welte173a1822020-12-03 15:36:59 +0100477 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_ROUTEING_AREA, 6))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200478 goto err_mand_ie;
Harald Welte560bdb32020-12-04 22:24:47 +0100479 from_bvc = gbproxy_bvc_by_nsei(cfg, nsei);
480 if (!from_bvc)
481 goto err_no_bvc;
482 memcpy(from_bvc->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
483 sizeof(from_bvc->ra));
484 gsm48_parse_ra(&raid, from_bvc->ra);
485 LOGPBVC(from_bvc, LOGL_INFO, "BSSGP SUSPEND/RESUME "
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100486 "RAI snooping: RAI %s\n",
487 osmo_rai_name(&raid));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200488 /* FIXME: This only supports one BSS per RA */
489 break;
490 case BSSGP_PDUT_BVC_RESET:
Harald Welte7a0c9dd2020-12-05 11:18:23 +0100491 rc = gbprox_rx_bvc_reset_from_bss(cfg, msg, nsei, &tp);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100492 /* if function retruns 0, we terminate processing here */
493 if (rc == 0)
494 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200495 break;
496 }
497
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200498 return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);
Harald Welte560bdb32020-12-04 22:24:47 +0100499err_no_bvc:
500 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/BSS) cannot find bvc based on NSEI\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200501 nsei);
502 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_NSEI]);
503 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
504err_mand_ie:
Daniel Willmann3696dce2020-12-02 16:08:02 +0100505 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/BSS) missing mandatory RA IE\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200506 nsei);
507 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
508 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
509}
510
511/* Receive paging request from SGSN, we need to relay to proper BSS */
512static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct tlv_parsed *tp,
513 uint32_t nsei, uint16_t ns_bvci)
514{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100515 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100516 struct gbproxy_bvc *bvc;
Daniel Willmann76205712020-11-30 17:08:58 +0100517 unsigned int n_nses = 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200518 int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
Harald Welte8b4c7942020-12-05 10:14:49 +0100519 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200520
Daniel Willmanne50550e2020-11-26 18:19:21 +0100521 /* FIXME: Handle paging logic to only page each matching NSE */
522
Daniel Willmann3696dce2020-12-02 16:08:02 +0100523 LOGP(DGPRS, LOGL_INFO, "NSE(%05u/SGSN) BSSGP PAGING\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200524 nsei);
Harald Welte173a1822020-12-03 15:36:59 +0100525 if (TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200526 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200527 errctr = GBPROX_GLOB_CTR_OTHER_ERR;
Harald Welte560bdb32020-12-04 22:24:47 +0100528 bvc = gbproxy_bvc_by_bvci(cfg, bvci);
529 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100530 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP PAGING: "
531 "unable to route: BVCI=%05u unknown\n", nsei, bvci);
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100532 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
533 return -EINVAL;
534 }
Harald Welte560bdb32020-12-04 22:24:47 +0100535 LOGPBVC(bvc, LOGL_INFO, "routing by BVCI\n");
536 return gbprox_relay2peer(msg, bvc, ns_bvci);
Harald Welte173a1822020-12-03 15:36:59 +0100537 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200538 errctr = GBPROX_GLOB_CTR_INV_RAI;
Harald Welte560bdb32020-12-04 22:24:47 +0100539 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +0100540 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100541 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100542 if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {
Daniel Willmann4becbcb2020-12-04 01:24:34 +0100543 LOGPNSE(nse, LOGL_INFO, "routing to NSE (RAI match)\n");
Harald Welte815f7982020-12-05 20:05:36 +0100544 gbprox_relay2peer(msg, bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +0100545 n_nses++;
546 /* Only send it once to each NSE */
547 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100548 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100549 }
550 }
Harald Welte173a1822020-12-03 15:36:59 +0100551 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_LOCATION_AREA, 5)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200552 errctr = GBPROX_GLOB_CTR_INV_LAI;
Harald Welte560bdb32020-12-04 22:24:47 +0100553 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +0100554 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100555 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100556 if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100557 LOGPNSE(nse, LOGL_INFO, "routing to NSE (LAI match)\n");
Harald Welte815f7982020-12-05 20:05:36 +0100558 gbprox_relay2peer(msg, bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +0100559 n_nses++;
560 /* Only send it once to each NSE */
561 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100562 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100563 }
564 }
Harald Welte173a1822020-12-03 15:36:59 +0100565 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1)) {
Harald Welte560bdb32020-12-04 22:24:47 +0100566 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +0100567 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100568 hash_for_each(nse->bvcs, j, bvc, list) {
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100569 LOGPNSE(nse, LOGL_INFO, "routing to NSE (broadcast)\n");
Harald Welte815f7982020-12-05 20:05:36 +0100570 gbprox_relay2peer(msg, bvc, ns_bvci);
Daniel Willmann76205712020-11-30 17:08:58 +0100571 n_nses++;
572 /* Only send it once to each NSE */
573 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100574 }
Harald Welte53ee2062020-11-24 11:31:13 +0100575 }
576 } else {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100577 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BSSGP PAGING: "
Harald Welte53ee2062020-11-24 11:31:13 +0100578 "unable to route, missing IE\n", nsei);
579 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
580 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200581
Daniel Willmann76205712020-11-30 17:08:58 +0100582 if (n_nses == 0) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100583 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BSSGP PAGING: "
Harald Welte53ee2062020-11-24 11:31:13 +0100584 "unable to route, no destination found\n", nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200585 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
586 return -EINVAL;
587 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100588 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200589}
590
591/* Receive an incoming BVC-RESET message from the SGSN */
592static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
593 struct msgb *orig_msg,
594 struct msgb *msg, struct tlv_parsed *tp,
595 uint32_t nsei, uint16_t ns_bvci)
596{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100597 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100598 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200599 uint16_t ptp_bvci;
Harald Welte8b4c7942020-12-05 10:14:49 +0100600 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200601
Harald Welte173a1822020-12-03 15:36:59 +0100602 if (!TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200603 rate_ctr_inc(&cfg->ctrg->
604 ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
605 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE,
606 NULL, orig_msg);
607 }
608 ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
609
610 if (ptp_bvci >= 2) {
611 /* A reset for a PTP BVC was received, forward it to its
Harald Welte560bdb32020-12-04 22:24:47 +0100612 * respective bvc */
613 bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);
614 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100615 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BVCI=%05u: Cannot find BSS\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200616 nsei, ptp_bvci);
617 rate_ctr_inc(&cfg->ctrg->
618 ctr[GBPROX_GLOB_CTR_INV_BVCI]);
619 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
620 &ptp_bvci, orig_msg);
621 }
Harald Welte560bdb32020-12-04 22:24:47 +0100622 return gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200623 }
624
625 /* A reset for the Signalling entity has been received
626 * from the SGSN. As the signalling BVCI is shared
627 * among all the BSS's that we multiplex, it needs to
628 * be relayed */
Harald Welted2fef952020-12-05 00:31:07 +0100629 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100630 hash_for_each(nse->bvcs, j, bvc, list)
Harald Welte560bdb32020-12-04 22:24:47 +0100631 gbprox_relay2peer(msg, bvc, ns_bvci);
Daniel Willmanne50550e2020-11-26 18:19:21 +0100632 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200633
634 return 0;
635}
636
637/* Receive an incoming signalling message from the SGSN-side NS-VC */
638static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg,
639 struct msgb *orig_msg, uint32_t nsei,
640 uint16_t ns_bvci)
641{
642 struct bssgp_normal_hdr *bgph =
643 (struct bssgp_normal_hdr *) msgb_bssgph(orig_msg);
644 struct tlv_parsed tp;
645 uint8_t pdu_type = bgph->pdu_type;
646 int data_len;
Harald Welte7479c4d2020-12-02 20:06:04 +0100647 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100648 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200649 uint16_t bvci;
650 struct msgb *msg;
Harald Welteec0f8012020-12-06 16:32:01 +0100651 char log_pfx[32];
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200652 int rc = 0;
653 int cause;
Harald Welted2fef952020-12-05 00:31:07 +0100654 int i;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200655
Harald Welteec0f8012020-12-06 16:32:01 +0100656 snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)", nsei);
657
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200658 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welteec0f8012020-12-06 16:32:01 +0100659 LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);
Harald Welte278dd272020-12-06 13:35:24 +0100660 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200661 }
662
Harald Welte278dd272020-12-06 13:35:24 +0100663 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
Harald Welteec0f8012020-12-06 16:32:01 +0100664 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx,
665 osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
Harald Welte278dd272020-12-06 13:35:24 +0100666 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
667 }
668
669 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_DL)) {
Harald Welteec0f8012020-12-06 16:32:01 +0100670 LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx,
671 osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200672 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
673 }
674
675 msg = bssgp_msgb_copy(orig_msg, "rx_sig_from_sgsn");
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200676 /* Update message info */
677 bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
678 data_len = msgb_bssgp_len(orig_msg) - sizeof(*bgph);
Harald Welteec0f8012020-12-06 16:32:01 +0100679
680 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, pdu_type, bgph->data, data_len, 0, 0,
681 DGPRS, log_pfx);
682 if (rc < 0) {
683 rc = tx_status_from_tlvp(rc, msg);
684 msgb_free(msg);
685 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
686 return rc;
687 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200688
689 switch (pdu_type) {
690 case BSSGP_PDUT_BVC_RESET:
691 rc = rx_reset_from_sgsn(cfg, msg, orig_msg, &tp, nsei, ns_bvci);
692 break;
693 case BSSGP_PDUT_BVC_RESET_ACK:
Daniel Willmann8489e7a2020-11-03 21:12:42 +0100694 /* simple case: BVCI IE is mandatory */
Harald Welte173a1822020-12-03 15:36:59 +0100695 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))
Daniel Willmann8489e7a2020-11-03 21:12:42 +0100696 goto err_mand_ie;
697 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
698 if (bvci == BVCI_SIGNALLING) {
699 /* TODO: Reset all PTP BVCIs */
700 } else {
701 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
702 }
703 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200704 case BSSGP_PDUT_FLUSH_LL:
705 /* simple case: BVCI IE is mandatory */
Harald Welte173a1822020-12-03 15:36:59 +0100706 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200707 goto err_mand_ie;
708 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
709 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
710 break;
711 case BSSGP_PDUT_PAGING_PS:
712 case BSSGP_PDUT_PAGING_CS:
713 /* process the paging request (LAI/RAI lookup) */
714 rc = gbprox_rx_paging(cfg, msg, &tp, nsei, ns_bvci);
715 break;
716 case BSSGP_PDUT_STATUS:
717 /* Some exception has occurred */
718 LOGP(DGPRS, LOGL_NOTICE,
Daniel Willmann3696dce2020-12-02 16:08:02 +0100719 "NSE(%05u/SGSN) BSSGP STATUS ", nsei);
Harald Welte173a1822020-12-03 15:36:59 +0100720 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_CAUSE, 1)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200721 LOGPC(DGPRS, LOGL_NOTICE, "\n");
722 goto err_mand_ie;
723 }
724 cause = *TLVP_VAL(&tp, BSSGP_IE_CAUSE);
725 LOGPC(DGPRS, LOGL_NOTICE,
726 "cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE),
727 bssgp_cause_str(cause));
Harald Welte173a1822020-12-03 15:36:59 +0100728 if (TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200729 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
Daniel Willmann3696dce2020-12-02 16:08:02 +0100730 LOGPC(DGPRS, LOGL_NOTICE, "BVCI=%05u\n", bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200731
732 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI)
733 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
734 } else
735 LOGPC(DGPRS, LOGL_NOTICE, "\n");
736 break;
737 /* those only exist in the SGSN -> BSS direction */
738 case BSSGP_PDUT_SUSPEND_ACK:
739 case BSSGP_PDUT_SUSPEND_NACK:
740 case BSSGP_PDUT_RESUME_ACK:
741 case BSSGP_PDUT_RESUME_NACK:
742 /* RAI IE is mandatory */
Harald Welte173a1822020-12-03 15:36:59 +0100743 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_ROUTEING_AREA, 6))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200744 goto err_mand_ie;
Harald Welte560bdb32020-12-04 22:24:47 +0100745 bvc = gbproxy_bvc_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
746 if (!bvc)
747 goto err_no_bvc;
748 rc = gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200749 break;
750 case BSSGP_PDUT_BVC_BLOCK_ACK:
751 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
Harald Welte173a1822020-12-03 15:36:59 +0100752 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200753 goto err_mand_ie;
754 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
755 if (bvci == 0) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100756 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP "
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200757 "%sBLOCK_ACK for signalling BVCI ?!?\n", nsei,
758 pdu_type == BSSGP_PDUT_BVC_UNBLOCK_ACK ? "UN":"");
Daniel Willmann65bfbaf2020-12-02 17:46:56 +0100759 /* TODO: should we send STATUS ? */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200760 rate_ctr_inc(&cfg->ctrg->
761 ctr[GBPROX_GLOB_CTR_INV_BVCI]);
762 } else {
763 /* Mark BVC as (un)blocked */
Harald Welte560bdb32020-12-04 22:24:47 +0100764 block_unblock_bvc(cfg, bvci, pdu_type);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200765 }
766 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
767 break;
768 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
Harald Welte7479c4d2020-12-02 20:06:04 +0100769 case BSSGP_PDUT_OVERLOAD:
770 LOGP(DGPRS, LOGL_DEBUG,
771 "NSE(%05u/SGSN) BSSGP %s: broadcasting\n", nsei, bssgp_pdu_str(pdu_type));
Harald Welte560bdb32020-12-04 22:24:47 +0100772 /* broadcast to all BSS-side bvcs */
Harald Welted2fef952020-12-05 00:31:07 +0100773 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte7479c4d2020-12-02 20:06:04 +0100774 gbprox_relay2nse(msg, nse, 0);
775 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200776 break;
777 default:
Daniel Willmann3696dce2020-12-02 16:08:02 +0100778 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP PDU type %s not supported\n", nsei,
779 bssgp_pdu_str(pdu_type));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200780 rate_ctr_inc(&cfg->ctrg->
781 ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
782 rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
783 break;
784 }
785
786 msgb_free(msg);
787
788 return rc;
789err_mand_ie:
Daniel Willmann3696dce2020-12-02 16:08:02 +0100790 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) missing mandatory IE\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200791 nsei);
792 rate_ctr_inc(&cfg->ctrg->
793 ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
794 msgb_free(msg);
795 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, orig_msg);
Harald Welte560bdb32020-12-04 22:24:47 +0100796err_no_bvc:
797 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) cannot find bvc based on RAI\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200798 nsei);
799 rate_ctr_inc(&cfg->ctrg-> ctr[GBPROX_GLOB_CTR_INV_RAI]);
800 msgb_free(msg);
801 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, orig_msg);
802}
803
Alexander Couzens951e1332020-09-22 13:21:46 +0200804int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200805{
806 int rc;
Alexander Couzens951e1332020-09-22 13:21:46 +0200807 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
808 struct gprs_ns2_inst *nsi = cfg->nsi;
809 struct osmo_gprs_ns2_prim nsp = {};
810
811 nsp.bvci = msgb_bvci(msg);
812 nsp.nsei = msgb_nsei(msg);
813
814 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA, PRIM_OP_REQUEST, msg);
815 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
816
817 return rc;
818}
819
820/* Main input function for Gb proxy */
821int gbprox_rcvmsg(void *ctx, struct msgb *msg)
822{
823 int rc;
824 uint16_t nsei = msgb_nsei(msg);
825 uint16_t ns_bvci = msgb_bvci(msg);
826 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
827
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200828 int remote_end_is_sgsn = gbproxy_is_sgsn_nsei(cfg, nsei);
829
Harald Welte278dd272020-12-06 13:35:24 +0100830 /* ensure minimum length to decode PCU type */
831 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
832 return bssgp_tx_status(BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
833
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200834 /* Only BVCI=0 messages need special treatment */
835 if (ns_bvci == 0 || ns_bvci == 1) {
836 if (remote_end_is_sgsn)
837 rc = gbprox_rx_sig_from_sgsn(cfg, msg, nsei, ns_bvci);
838 else
839 rc = gbprox_rx_sig_from_bss(cfg, msg, nsei, ns_bvci);
840 } else {
841 /* All other BVCI are PTP */
842 if (remote_end_is_sgsn)
Alexander Couzens951e1332020-09-22 13:21:46 +0200843 rc = gbprox_rx_ptp_from_sgsn(cfg, msg, nsei,
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200844 ns_bvci);
845 else
Alexander Couzens951e1332020-09-22 13:21:46 +0200846 rc = gbprox_rx_ptp_from_bss(cfg, msg, nsei,
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200847 ns_bvci);
848 }
849
850 return rc;
851}
852
Alexander Couzens951e1332020-09-22 13:21:46 +0200853/* TODO: What about handling:
854 * NS_AFF_CAUSE_VC_FAILURE,
855 NS_AFF_CAUSE_VC_RECOVERY,
856 NS_AFF_CAUSE_FAILURE,
857 NS_AFF_CAUSE_RECOVERY,
858 osmocom own causes
859 NS_AFF_CAUSE_SNS_CONFIGURED,
860 NS_AFF_CAUSE_SNS_FAILURE,
861 */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200862
Alexander Couzens951e1332020-09-22 13:21:46 +0200863void gprs_ns_prim_status_cb(struct gbproxy_config *cfg, struct osmo_gprs_ns2_prim *nsp)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200864{
Harald Welte560bdb32020-12-04 22:24:47 +0100865 /* TODO: bss nsei available/unavailable bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, nsvc->nsei, bvc->bvci, 0);
Alexander Couzens951e1332020-09-22 13:21:46 +0200866 * TODO: sgsn nsei available/unavailable
867 */
Harald Welte560bdb32020-12-04 22:24:47 +0100868 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200869
Alexander Couzens951e1332020-09-22 13:21:46 +0200870 switch (nsp->u.status.cause) {
871 case NS_AFF_CAUSE_SNS_FAILURE:
872 case NS_AFF_CAUSE_SNS_CONFIGURED:
873 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200874
Alexander Couzens951e1332020-09-22 13:21:46 +0200875 case NS_AFF_CAUSE_RECOVERY:
876 LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);
Harald Weltea0f70732020-12-05 17:50:23 +0100877 if (gbproxy_is_sgsn_nsei(cfg, nsp->nsei)) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200878 /* look-up or create the BTS context for this BVC */
879 struct bssgp_bvc_ctx *bctx = btsctx_by_bvci_nsei(nsp->bvci, nsp->nsei);
880 if (!bctx)
881 bctx = btsctx_alloc(nsp->bvci, nsp->nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200882
Alexander Couzens951e1332020-09-22 13:21:46 +0200883 bssgp_tx_bvc_reset_nsei_bvci(cfg->nsip_sgsn_nsei, 0, BSSGP_CAUSE_OML_INTERV, NULL, 0);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200884 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200885 break;
886 case NS_AFF_CAUSE_FAILURE:
Harald Weltea0f70732020-12-05 17:50:23 +0100887 if (gbproxy_is_sgsn_nsei(cfg, nsp->nsei)) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200888 /* sgsn */
889 /* TODO: BSVC: block all PtP towards bss */
890 rate_ctr_inc(&cfg->ctrg->
891 ctr[GBPROX_GLOB_CTR_RESTART_RESET_SGSN]);
892 } else {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100893 /* bss became unavailable
894 * TODO: Block all BVC belonging to that NSE */
Harald Welte560bdb32020-12-04 22:24:47 +0100895 bvc = gbproxy_bvc_by_nsei(cfg, nsp->nsei);
896 if (!bvc) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200897 /* TODO: use primitive name + status cause name */
Harald Welte560bdb32020-12-04 22:24:47 +0100898 LOGP(DGPRS, LOGL_NOTICE, "Received ns2 primitive %d for unknown bvc NSEI=%u\n",
Alexander Couzens951e1332020-09-22 13:21:46 +0200899 nsp->u.status.cause, nsp->nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200900 break;
901 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200902
Harald Welte560bdb32020-12-04 22:24:47 +0100903 if (!bvc->blocked)
Alexander Couzens951e1332020-09-22 13:21:46 +0200904 break;
905 bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, cfg->nsip_sgsn_nsei,
Harald Welte560bdb32020-12-04 22:24:47 +0100906 bvc->bvci, 0);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200907 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200908 LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);
909 break;
910 default:
Harald Welte95cf9fb2020-11-30 10:55:22 +0100911 LOGP(DPCU, LOGL_NOTICE, "NS: Unknown NS-STATUS.ind cause=%s from NS\n",
912 gprs_ns2_aff_cause_prim_str(nsp->u.status.cause));
Alexander Couzens951e1332020-09-22 13:21:46 +0200913 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200914 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200915}
916
Alexander Couzens951e1332020-09-22 13:21:46 +0200917/* called by the ns layer */
918int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
919{
920 struct osmo_gprs_ns2_prim *nsp;
921 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Daniel Willmann8f407b12020-12-02 19:33:50 +0100922 uintptr_t bvci;
Alexander Couzens951e1332020-09-22 13:21:46 +0200923 int rc = 0;
924
925 if (oph->sap != SAP_NS)
926 return 0;
927
928 nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
929
930 if (oph->operation != PRIM_OP_INDICATION) {
Harald Welte95cf9fb2020-11-30 10:55:22 +0100931 LOGP(DPCU, LOGL_NOTICE, "NS: Unexpected primitive operation %s from NS\n",
932 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +0200933 return 0;
934 }
935
936 switch (oph->primitive) {
937 case PRIM_NS_UNIT_DATA:
Daniel Willmann8f407b12020-12-02 19:33:50 +0100938
Alexander Couzens951e1332020-09-22 13:21:46 +0200939 /* hand the message into the BSSGP implementation */
940 msgb_bssgph(oph->msg) = oph->msg->l3h;
941 msgb_bvci(oph->msg) = nsp->bvci;
942 msgb_nsei(oph->msg) = nsp->nsei;
Daniel Willmann8f407b12020-12-02 19:33:50 +0100943 bvci = nsp->bvci | BVC_LOG_CTX_FLAG;
Alexander Couzens951e1332020-09-22 13:21:46 +0200944
Daniel Willmann8f407b12020-12-02 19:33:50 +0100945 log_set_context(LOG_CTX_GB_BVC, (void *)bvci);
Alexander Couzens951e1332020-09-22 13:21:46 +0200946 rc = gbprox_rcvmsg(cfg, oph->msg);
Daniel Willmannb6550102020-11-04 17:32:56 +0100947 msgb_free(oph->msg);
Alexander Couzens951e1332020-09-22 13:21:46 +0200948 break;
949 case PRIM_NS_STATUS:
950 gprs_ns_prim_status_cb(cfg, nsp);
951 break;
952 default:
Harald Welte95cf9fb2020-11-30 10:55:22 +0100953 LOGP(DPCU, LOGL_NOTICE, "NS: Unknown prim %s %s from NS\n",
954 gprs_ns2_prim_str(oph->primitive),
955 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +0200956 break;
957 }
958
959 return rc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200960}
961
962void gbprox_reset(struct gbproxy_config *cfg)
963{
Harald Welted2fef952020-12-05 00:31:07 +0100964 struct gbproxy_nse *nse;
965 struct hlist_node *ntmp;
Harald Welte8b4c7942020-12-05 10:14:49 +0100966 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200967
Harald Welted2fef952020-12-05 00:31:07 +0100968 hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100969 struct gbproxy_bvc *bvc;
970 struct hlist_node *tmp;
971 hash_for_each_safe(nse->bvcs, j, tmp, bvc, list)
Harald Welte560bdb32020-12-04 22:24:47 +0100972 gbproxy_bvc_free(bvc);
Daniel Willmanne50550e2020-11-26 18:19:21 +0100973
974 gbproxy_nse_free(nse);
975 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200976
977 rate_ctr_group_free(cfg->ctrg);
978 gbproxy_init_config(cfg);
979}
980
981int gbproxy_init_config(struct gbproxy_config *cfg)
982{
983 struct timespec tp;
984
Harald Welted2fef952020-12-05 00:31:07 +0100985 hash_init(cfg->bss_nses);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200986 cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
987 if (!cfg->ctrg) {
988 LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
989 return -1;
990 }
991 osmo_clock_gettime(CLOCK_REALTIME, &tp);
Harald Weltec169de42020-12-07 13:12:13 +0100992 osmo_fsm_log_timeouts(true);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200993
994 return 0;
995}