blob: a30f5ad16cb6ab3e4454b5456a7135411eca8615 [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
107/* strip off the NS header */
108static void strip_ns_hdr(struct msgb *msg)
109{
110 int strip_len = msgb_bssgph(msg) - msg->data;
111 msgb_pull(msg, strip_len);
112}
113
Harald Welte560bdb32020-12-04 22:24:47 +0100114/* feed a message down the NS-VC associated with the specified bvc */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200115static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
116 uint16_t ns_bvci, uint16_t sgsn_nsei)
117{
118 /* create a copy of the message so the old one can
119 * be free()d safely when we return from gbprox_rcvmsg() */
Alexander Couzens951e1332020-09-22 13:21:46 +0200120 struct gprs_ns2_inst *nsi = cfg->nsi;
121 struct osmo_gprs_ns2_prim nsp = {};
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200122 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2sgsn");
123 int rc;
124
Daniel Willmann3696dce2020-12-02 16:08:02 +0100125 DEBUGP(DGPRS, "NSE(%05u/BSS)-BVC(%05u) proxying BTS->SGSN NSE(%05u/SGSN)\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200126 msgb_nsei(msg), ns_bvci, sgsn_nsei);
127
Alexander Couzens951e1332020-09-22 13:21:46 +0200128 nsp.bvci = ns_bvci;
129 nsp.nsei = sgsn_nsei;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200130
131 strip_ns_hdr(msg);
Alexander Couzens951e1332020-09-22 13:21:46 +0200132 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA,
133 PRIM_OP_REQUEST, msg);
134 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200135 if (rc < 0)
136 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_TX_ERR_SGSN]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200137 return rc;
138}
139
Daniel Willmann76205712020-11-30 17:08:58 +0100140/* feed a message down the NSE */
141static int gbprox_relay2nse(struct msgb *old_msg, struct gbproxy_nse *nse,
Daniel Willmann35f7d332020-11-03 21:11:45 +0100142 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200143{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100144 OSMO_ASSERT(nse);
145 OSMO_ASSERT(nse->cfg);
146
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200147 /* create a copy of the message so the old one can
148 * be free()d safely when we return from gbprox_rcvmsg() */
Daniel Willmanne50550e2020-11-26 18:19:21 +0100149 struct gprs_ns2_inst *nsi = nse->cfg->nsi;
Alexander Couzens951e1332020-09-22 13:21:46 +0200150 struct osmo_gprs_ns2_prim nsp = {};
Daniel Willmann76205712020-11-30 17:08:58 +0100151 struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2nse");
Harald Weltefe059582020-11-18 12:01:46 +0100152 uint32_t tlli;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200153 int rc;
154
Daniel Willmann3696dce2020-12-02 16:08:02 +0100155 DEBUGP(DGPRS, "NSE(%05u/SGSN)-BVC(%05u) proxying SGSN->BSS NSE(%05u/BSS)\n",
Daniel Willmanne50550e2020-11-26 18:19:21 +0100156 msgb_nsei(msg), ns_bvci, nse->nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200157
Alexander Couzens951e1332020-09-22 13:21:46 +0200158 nsp.bvci = ns_bvci;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100159 nsp.nsei = nse->nsei;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200160
161 /* Strip the old NS header, it will be replaced with a new one */
162 strip_ns_hdr(msg);
163
Harald Weltefe059582020-11-18 12:01:46 +0100164 /* TS 48.018 Section 5.4.2: The link selector parameter is
165 * defined in 3GPP TS 48.016. At one side of the Gb interface,
166 * all BSSGP UNITDATA PDUs related to an MS shall be passed with
167 * the same LSP, e.g. the LSP contains the MS's TLLI, to the
168 * underlying network service. */
169 if (gprs_gb_parse_tlli(msgb_data(msg), msgb_length(msg), &tlli) == 1)
170 nsp.u.unitdata.link_selector = tlli;
171
Alexander Couzens951e1332020-09-22 13:21:46 +0200172 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA,
173 PRIM_OP_REQUEST, msg);
174 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
Daniel Willmann76205712020-11-30 17:08:58 +0100175 /* FIXME: We need a counter group for gbproxy_nse */
176 //if (rc < 0)
Harald Welte560bdb32020-12-04 22:24:47 +0100177 // rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_TX_ERR]);
Daniel Willmann76205712020-11-30 17:08:58 +0100178
179 return rc;
180}
181
Harald Welte560bdb32020-12-04 22:24:47 +0100182/* feed a message down the NS-VC associated with the specified bvc */
183static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,
Daniel Willmann76205712020-11-30 17:08:58 +0100184 uint16_t ns_bvci)
185{
186 int rc;
Harald Welte560bdb32020-12-04 22:24:47 +0100187 struct gbproxy_nse *nse = bvc->nse;
Daniel Willmann76205712020-11-30 17:08:58 +0100188 OSMO_ASSERT(nse);
189
190 rc = gbprox_relay2nse(old_msg, nse, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200191 if (rc < 0)
Harald Welte560bdb32020-12-04 22:24:47 +0100192 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_TX_ERR]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200193
194 return rc;
195}
196
Harald Welte560bdb32020-12-04 22:24:47 +0100197static int block_unblock_bvc(struct gbproxy_config *cfg, uint16_t ptp_bvci, uint8_t pdu_type)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200198{
Harald Welte560bdb32020-12-04 22:24:47 +0100199 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200200
Harald Welte560bdb32020-12-04 22:24:47 +0100201 bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);
202 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100203 LOGP(DGPRS, LOGL_ERROR, "BVC(%05u/??) Cannot find BSS\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200204 ptp_bvci);
205 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);
206 return -ENOENT;
207 }
208
209 switch (pdu_type) {
210 case BSSGP_PDUT_BVC_BLOCK_ACK:
Harald Welte560bdb32020-12-04 22:24:47 +0100211 bvc->blocked = true;
212 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_BLOCKED]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200213 break;
214 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
Harald Welte560bdb32020-12-04 22:24:47 +0100215 bvc->blocked = false;
216 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_UNBLOCKED]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200217 break;
218 default:
219 break;
220 }
221 return 0;
222}
223
Harald Welte560bdb32020-12-04 22:24:47 +0100224/* Send a message to a bvc identified by ptp_bvci but using ns_bvci
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200225 * in the NS hdr */
226static int gbprox_relay2bvci(struct gbproxy_config *cfg, struct msgb *msg, uint16_t ptp_bvci,
227 uint16_t ns_bvci)
228{
Harald Welte560bdb32020-12-04 22:24:47 +0100229 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200230
Harald Welte560bdb32020-12-04 22:24:47 +0100231 bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);
232 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100233 LOGP(DGPRS, LOGL_ERROR, "BVC(%05u/??) Cannot find BSS\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200234 ptp_bvci);
235 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);
236 return -ENOENT;
237 }
238
Harald Welte560bdb32020-12-04 22:24:47 +0100239 return gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200240}
241
242int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
243{
244 return 0;
245}
246
247/* Receive an incoming PTP message from a BSS-side NS-VC */
248static int gbprox_rx_ptp_from_bss(struct gbproxy_config *cfg,
249 struct msgb *msg, uint16_t nsei,
Alexander Couzens951e1332020-09-22 13:21:46 +0200250 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200251{
Harald Welte278dd272020-12-06 13:35:24 +0100252 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte560bdb32020-12-04 22:24:47 +0100253 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200254
Harald Welte278dd272020-12-06 13:35:24 +0100255 if (ns_bvci == 0 && ns_bvci == 1) {
256 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) BVCI=%05u is not PTP\n", nsei, ns_bvci);
257 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
258 }
259
260 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
261 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in PTP BVC\n",
262 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
263 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
264 }
265
266 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_UL)) {
267 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in uplink direction\n",
268 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
269 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
270 }
271
Harald Welte560bdb32020-12-04 22:24:47 +0100272 bvc = gbproxy_bvc_by_bvci(cfg, ns_bvci);
273 if (!bvc) {
274 LOGP(DGPRS, LOGL_NOTICE, "BVC(%05u/??) Didn't find bvc "
Daniel Willmann3696dce2020-12-02 16:08:02 +0100275 "for PTP message from NSE(%05u/BSS), "
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200276 "discarding message\n",
Alexander Couzens951e1332020-09-22 13:21:46 +0200277 ns_bvci, nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200278 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
279 &ns_bvci, msg);
280 }
281
Daniel Willmann65bfbaf2020-12-02 17:46:56 +0100282 /* TODO: Should we discard this message if the check fails */
Harald Welte560bdb32020-12-04 22:24:47 +0100283 check_bvc_nsei(bvc, nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200284
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200285 return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);
286}
287
288/* Receive an incoming PTP message from a SGSN-side NS-VC */
289static int gbprox_rx_ptp_from_sgsn(struct gbproxy_config *cfg,
290 struct msgb *msg, uint16_t nsei,
Alexander Couzens951e1332020-09-22 13:21:46 +0200291 uint16_t ns_bvci)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200292{
Harald Welte278dd272020-12-06 13:35:24 +0100293 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welte560bdb32020-12-04 22:24:47 +0100294 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200295
Harald Welte278dd272020-12-06 13:35:24 +0100296 if (ns_bvci == 0 && ns_bvci == 1) {
297 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) BVCI=%05u is not PTP\n", nsei, ns_bvci);
298 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
299 }
300
301 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {
302 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in PTP BVC\n",
303 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
304 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
305 }
306
307 if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_DL)) {
308 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in downlink direction\n",
309 nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));
310 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
311 }
312
Harald Welte560bdb32020-12-04 22:24:47 +0100313 bvc = gbproxy_bvc_by_bvci(cfg, ns_bvci);
Harald Welte560bdb32020-12-04 22:24:47 +0100314 if (!bvc) {
315 LOGP(DGPRS, LOGL_INFO, "BVC(%05u/??) Didn't find bvc for "
Daniel Willmann3696dce2020-12-02 16:08:02 +0100316 "for message from NSE(%05u/SGSN)\n",
Alexander Couzens951e1332020-09-22 13:21:46 +0200317 ns_bvci, nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200318 rate_ctr_inc(&cfg->ctrg->
319 ctr[GBPROX_GLOB_CTR_INV_BVCI]);
320 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
321 &ns_bvci, msg);
322 }
323
Harald Welte560bdb32020-12-04 22:24:47 +0100324 if (bvc->blocked) {
325 LOGPBVC(bvc, LOGL_NOTICE, "Dropping PDU for "
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100326 "blocked BVC via NSE(%05u/SGSN)\n", nsei);
Harald Welte560bdb32020-12-04 22:24:47 +0100327 rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_DROPPED]);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200328 return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &ns_bvci, msg);
329 }
330
Harald Welte560bdb32020-12-04 22:24:47 +0100331 return gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200332}
333
Harald Welte7df1e5a2020-12-02 22:53:26 +0100334/* process a BVC-RESET message from the BSS side */
335static int gbprox_rx_bvc_reset_from_bss(struct gbproxy_config *cfg, struct msgb *msg,
Harald Welte7a0c9dd2020-12-05 11:18:23 +0100336 uint16_t nsei, struct tlv_parsed *tp)
Harald Welte7df1e5a2020-12-02 22:53:26 +0100337{
Harald Welte560bdb32020-12-04 22:24:47 +0100338 struct gbproxy_bvc *from_bvc = NULL;
Harald Welte314647b2020-12-02 23:03:22 +0100339 uint16_t bvci;
Harald Welte7df1e5a2020-12-02 22:53:26 +0100340
Harald Welte173a1822020-12-03 15:36:59 +0100341 if (!TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2) || !TLVP_PRES_LEN(tp, BSSGP_IE_CAUSE, 1)) {
Harald Weltef9e149b2020-12-02 23:29:38 +0100342 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
343 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
344 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100345
Harald Welte314647b2020-12-02 23:03:22 +0100346 bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
347 LOGP(DGPRS, LOGL_INFO, "NSE(%05u) Rx BVC RESET (BVCI=%05u)\n", nsei, bvci);
348 if (bvci == 0) {
349 /* If we receive a BVC reset on the signalling endpoint, we
350 * don't want the SGSN to reset, as the signalling endpoint
351 * is common for all point-to-point BVCs (and thus all BTS) */
Harald Welte324f0652020-12-02 23:06:37 +0100352
Harald Welte560bdb32020-12-04 22:24:47 +0100353 /* Ensure the NSE bvc is there and clear all PtP BVCs */
Harald Welte324f0652020-12-02 23:06:37 +0100354 struct gbproxy_nse *nse = gbproxy_nse_by_nsei_or_new(cfg, nsei);
Harald Welte314647b2020-12-02 23:03:22 +0100355 if (!nse) {
356 LOGP(DGPRS, LOGL_ERROR, "Could not create NSE(%05u)\n", nsei);
357 bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, 0, msg);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100358 return 0;
359 }
Harald Welte314647b2020-12-02 23:03:22 +0100360
Harald Welte560bdb32020-12-04 22:24:47 +0100361 gbproxy_cleanup_bvcs(cfg, nsei, 0);
Harald Welte314647b2020-12-02 23:03:22 +0100362
363 /* FIXME: only do this if SGSN is alive! */
Harald Welte324f0652020-12-02 23:06:37 +0100364 LOGPNSE(nse, LOGL_INFO, "Tx fake BVC RESET ACK of BVCI=0\n");
Harald Welte314647b2020-12-02 23:03:22 +0100365 bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsei, 0, 0);
366 return 0;
367 } else {
Harald Welte560bdb32020-12-04 22:24:47 +0100368 from_bvc = gbproxy_bvc_by_bvci(cfg, bvci);
369 if (!from_bvc) {
Harald Welte7df1e5a2020-12-02 22:53:26 +0100370 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(cfg, nsei);
371 if (!nse) {
372 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "
373 "BVCI=%05u\n", nsei, bvci);
374 bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, NULL, msg);
375 return 0;
376 }
377 /* if a PTP-BVC is reset, and we don't know that
Harald Welte560bdb32020-12-04 22:24:47 +0100378 * PTP-BVCI yet, we should allocate a new bvc */
379 from_bvc = gbproxy_bvc_alloc(nse, bvci);
380 OSMO_ASSERT(from_bvc);
381 LOGPBVC(from_bvc, LOGL_INFO, "Allocated new bvc\n");
Harald Welte7df1e5a2020-12-02 22:53:26 +0100382 }
383
384 /* Could have moved to a different NSE */
Harald Welte560bdb32020-12-04 22:24:47 +0100385 if (!check_bvc_nsei(from_bvc, nsei)) {
386 LOGPBVC(from_bvc, LOGL_NOTICE, "moving bvc to NSE(%05u)\n", nsei);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100387
388 struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei(cfg, nsei);
389 if (!nse_new) {
390 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "
391 "BVCI=%05u\n", bvci, nsei);
392 bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, NULL, msg);
393 return 0;
394 }
395
Harald Welte560bdb32020-12-04 22:24:47 +0100396 /* Move bvc to different NSE */
397 gbproxy_bvc_move(from_bvc, nse_new);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100398 }
399
Harald Welte173a1822020-12-03 15:36:59 +0100400 if (TLVP_PRES_LEN(tp, BSSGP_IE_CELL_ID, 8)) {
Harald Welte7df1e5a2020-12-02 22:53:26 +0100401 struct gprs_ra_id raid;
402 /* We have a Cell Identifier present in this
403 * PDU, this means we can extend our local
404 * state information about this particular cell
405 * */
Harald Welte560bdb32020-12-04 22:24:47 +0100406 memcpy(from_bvc->ra, TLVP_VAL(tp, BSSGP_IE_CELL_ID), sizeof(from_bvc->ra));
407 gsm48_parse_ra(&raid, from_bvc->ra);
408 LOGPBVC(from_bvc, LOGL_INFO, "Cell ID %s\n", osmo_rai_name(&raid));
Harald Welte7df1e5a2020-12-02 22:53:26 +0100409 }
Harald Welte7df1e5a2020-12-02 22:53:26 +0100410 }
411 /* continue processing / relaying to SGSN[s] */
412 return 1;
413}
414
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200415/* Receive an incoming signalling message from a BSS-side NS-VC */
416static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg,
417 struct msgb *msg, uint16_t nsei,
418 uint16_t ns_bvci)
419{
420 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
421 struct tlv_parsed tp;
422 uint8_t pdu_type = bgph->pdu_type;
423 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welte560bdb32020-12-04 22:24:47 +0100424 struct gbproxy_bvc *from_bvc = NULL;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200425 struct gprs_ra_id raid;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200426 int rc;
427
428 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welte278dd272020-12-06 13:35:24 +0100429 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) BVCI=%05u is not signalling\n", nsei, ns_bvci);
430 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200431 }
432
Harald Welte278dd272020-12-06 13:35:24 +0100433 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
434 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) %s not allowed in signalling BVC\n",
435 nsei, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
436 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
437 }
438
439 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_UL)) {
440 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) %s not allowed in uplink direction\n",
441 nsei, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
442 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200443 }
444
445 bssgp_tlv_parse(&tp, bgph->data, data_len);
446
447 switch (pdu_type) {
448 case BSSGP_PDUT_SUSPEND:
449 case BSSGP_PDUT_RESUME:
450 /* We implement RAI snooping during SUSPEND/RESUME, since it
Harald Welte560bdb32020-12-04 22:24:47 +0100451 * establishes a relationsip between BVCI/bvc and the routeing
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200452 * area identification. The snooped information is then used
453 * for routing the {SUSPEND,RESUME}_[N]ACK back to the correct
454 * BSSGP */
Harald Welte173a1822020-12-03 15:36:59 +0100455 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_ROUTEING_AREA, 6))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200456 goto err_mand_ie;
Harald Welte560bdb32020-12-04 22:24:47 +0100457 from_bvc = gbproxy_bvc_by_nsei(cfg, nsei);
458 if (!from_bvc)
459 goto err_no_bvc;
460 memcpy(from_bvc->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
461 sizeof(from_bvc->ra));
462 gsm48_parse_ra(&raid, from_bvc->ra);
463 LOGPBVC(from_bvc, LOGL_INFO, "BSSGP SUSPEND/RESUME "
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100464 "RAI snooping: RAI %s\n",
465 osmo_rai_name(&raid));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200466 /* FIXME: This only supports one BSS per RA */
467 break;
468 case BSSGP_PDUT_BVC_RESET:
Harald Welte7a0c9dd2020-12-05 11:18:23 +0100469 rc = gbprox_rx_bvc_reset_from_bss(cfg, msg, nsei, &tp);
Harald Welte7df1e5a2020-12-02 22:53:26 +0100470 /* if function retruns 0, we terminate processing here */
471 if (rc == 0)
472 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200473 break;
474 }
475
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200476 return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);
Harald Welte560bdb32020-12-04 22:24:47 +0100477err_no_bvc:
478 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/BSS) cannot find bvc based on NSEI\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200479 nsei);
480 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_NSEI]);
481 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
482err_mand_ie:
Daniel Willmann3696dce2020-12-02 16:08:02 +0100483 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/BSS) missing mandatory RA IE\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200484 nsei);
485 rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
486 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
487}
488
489/* Receive paging request from SGSN, we need to relay to proper BSS */
490static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct tlv_parsed *tp,
491 uint32_t nsei, uint16_t ns_bvci)
492{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100493 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100494 struct gbproxy_bvc *bvc;
Daniel Willmann76205712020-11-30 17:08:58 +0100495 unsigned int n_nses = 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200496 int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
Harald Welte8b4c7942020-12-05 10:14:49 +0100497 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200498
Daniel Willmanne50550e2020-11-26 18:19:21 +0100499 /* FIXME: Handle paging logic to only page each matching NSE */
500
Daniel Willmann3696dce2020-12-02 16:08:02 +0100501 LOGP(DGPRS, LOGL_INFO, "NSE(%05u/SGSN) BSSGP PAGING\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200502 nsei);
Harald Welte173a1822020-12-03 15:36:59 +0100503 if (TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200504 uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200505 errctr = GBPROX_GLOB_CTR_OTHER_ERR;
Harald Welte560bdb32020-12-04 22:24:47 +0100506 bvc = gbproxy_bvc_by_bvci(cfg, bvci);
507 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100508 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP PAGING: "
509 "unable to route: BVCI=%05u unknown\n", nsei, bvci);
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100510 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
511 return -EINVAL;
512 }
Harald Welte560bdb32020-12-04 22:24:47 +0100513 LOGPBVC(bvc, LOGL_INFO, "routing by BVCI\n");
514 return gbprox_relay2peer(msg, bvc, ns_bvci);
Harald Welte173a1822020-12-03 15:36:59 +0100515 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200516 errctr = GBPROX_GLOB_CTR_INV_RAI;
Harald Welte560bdb32020-12-04 22:24:47 +0100517 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +0100518 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100519 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100520 if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {
Daniel Willmann4becbcb2020-12-04 01:24:34 +0100521 LOGPNSE(nse, LOGL_INFO, "routing to NSE (RAI match)\n");
Daniel Willmann76205712020-11-30 17:08:58 +0100522 gbprox_relay2nse(msg, nse, ns_bvci);
523 n_nses++;
524 /* Only send it once to each NSE */
525 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100526 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100527 }
528 }
Harald Welte173a1822020-12-03 15:36:59 +0100529 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_LOCATION_AREA, 5)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200530 errctr = GBPROX_GLOB_CTR_INV_LAI;
Harald Welte560bdb32020-12-04 22:24:47 +0100531 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +0100532 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100533 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100534 if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100535 LOGPNSE(nse, LOGL_INFO, "routing to NSE (LAI match)\n");
Daniel Willmann76205712020-11-30 17:08:58 +0100536 gbprox_relay2nse(msg, nse, ns_bvci);
537 n_nses++;
538 /* Only send it once to each NSE */
539 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100540 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100541 }
542 }
Harald Welte173a1822020-12-03 15:36:59 +0100543 } else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1)) {
Harald Welte560bdb32020-12-04 22:24:47 +0100544 /* iterate over all bvcs and dispatch the paging to each matching one */
Harald Welted2fef952020-12-05 00:31:07 +0100545 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100546 hash_for_each(nse->bvcs, j, bvc, list) {
Daniel Willmann5e595ca2020-12-02 13:54:21 +0100547 LOGPNSE(nse, LOGL_INFO, "routing to NSE (broadcast)\n");
Daniel Willmann76205712020-11-30 17:08:58 +0100548 gbprox_relay2nse(msg, nse, ns_bvci);
549 n_nses++;
550 /* Only send it once to each NSE */
551 break;
Daniel Willmanne50550e2020-11-26 18:19:21 +0100552 }
Harald Welte53ee2062020-11-24 11:31:13 +0100553 }
554 } else {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100555 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BSSGP PAGING: "
Harald Welte53ee2062020-11-24 11:31:13 +0100556 "unable to route, missing IE\n", nsei);
557 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
558 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200559
Daniel Willmann76205712020-11-30 17:08:58 +0100560 if (n_nses == 0) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100561 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BSSGP PAGING: "
Harald Welte53ee2062020-11-24 11:31:13 +0100562 "unable to route, no destination found\n", nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200563 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
564 return -EINVAL;
565 }
Harald Welte3d1bd4d2020-11-23 15:14:20 +0100566 return 0;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200567}
568
569/* Receive an incoming BVC-RESET message from the SGSN */
570static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
571 struct msgb *orig_msg,
572 struct msgb *msg, struct tlv_parsed *tp,
573 uint32_t nsei, uint16_t ns_bvci)
574{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100575 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100576 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200577 uint16_t ptp_bvci;
Harald Welte8b4c7942020-12-05 10:14:49 +0100578 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200579
Harald Welte173a1822020-12-03 15:36:59 +0100580 if (!TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200581 rate_ctr_inc(&cfg->ctrg->
582 ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
583 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE,
584 NULL, orig_msg);
585 }
586 ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
587
588 if (ptp_bvci >= 2) {
589 /* A reset for a PTP BVC was received, forward it to its
Harald Welte560bdb32020-12-04 22:24:47 +0100590 * respective bvc */
591 bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);
592 if (!bvc) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100593 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BVCI=%05u: Cannot find BSS\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200594 nsei, ptp_bvci);
595 rate_ctr_inc(&cfg->ctrg->
596 ctr[GBPROX_GLOB_CTR_INV_BVCI]);
597 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
598 &ptp_bvci, orig_msg);
599 }
Harald Welte560bdb32020-12-04 22:24:47 +0100600 return gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200601 }
602
603 /* A reset for the Signalling entity has been received
604 * from the SGSN. As the signalling BVCI is shared
605 * among all the BSS's that we multiplex, it needs to
606 * be relayed */
Harald Welted2fef952020-12-05 00:31:07 +0100607 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100608 hash_for_each(nse->bvcs, j, bvc, list)
Harald Welte560bdb32020-12-04 22:24:47 +0100609 gbprox_relay2peer(msg, bvc, ns_bvci);
Daniel Willmanne50550e2020-11-26 18:19:21 +0100610 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200611
612 return 0;
613}
614
615/* Receive an incoming signalling message from the SGSN-side NS-VC */
616static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg,
617 struct msgb *orig_msg, uint32_t nsei,
618 uint16_t ns_bvci)
619{
620 struct bssgp_normal_hdr *bgph =
621 (struct bssgp_normal_hdr *) msgb_bssgph(orig_msg);
622 struct tlv_parsed tp;
623 uint8_t pdu_type = bgph->pdu_type;
624 int data_len;
Harald Welte7479c4d2020-12-02 20:06:04 +0100625 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100626 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200627 uint16_t bvci;
628 struct msgb *msg;
629 int rc = 0;
630 int cause;
Harald Welted2fef952020-12-05 00:31:07 +0100631 int i;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200632
633 if (ns_bvci != 0 && ns_bvci != 1) {
Harald Welte278dd272020-12-06 13:35:24 +0100634 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BVCI=%05u is not signalling\n", nsei, ns_bvci);
635 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200636 }
637
Harald Welte278dd272020-12-06 13:35:24 +0100638 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {
639 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) %s not allowed in signalling BVC\n",
640 nsei, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
641 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
642 }
643
644 if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_DL)) {
645 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) %s not allowed in downlink direction\n",
646 nsei, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200647 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
648 }
649
650 msg = bssgp_msgb_copy(orig_msg, "rx_sig_from_sgsn");
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200651 /* Update message info */
652 bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
653 data_len = msgb_bssgp_len(orig_msg) - sizeof(*bgph);
654 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
655
656 switch (pdu_type) {
657 case BSSGP_PDUT_BVC_RESET:
658 rc = rx_reset_from_sgsn(cfg, msg, orig_msg, &tp, nsei, ns_bvci);
659 break;
660 case BSSGP_PDUT_BVC_RESET_ACK:
Daniel Willmann8489e7a2020-11-03 21:12:42 +0100661 /* simple case: BVCI IE is mandatory */
Harald Welte173a1822020-12-03 15:36:59 +0100662 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))
Daniel Willmann8489e7a2020-11-03 21:12:42 +0100663 goto err_mand_ie;
664 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
665 if (bvci == BVCI_SIGNALLING) {
666 /* TODO: Reset all PTP BVCIs */
667 } else {
668 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
669 }
670 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200671 case BSSGP_PDUT_FLUSH_LL:
672 /* simple case: BVCI IE is mandatory */
Harald Welte173a1822020-12-03 15:36:59 +0100673 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200674 goto err_mand_ie;
675 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
676 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
677 break;
678 case BSSGP_PDUT_PAGING_PS:
679 case BSSGP_PDUT_PAGING_CS:
680 /* process the paging request (LAI/RAI lookup) */
681 rc = gbprox_rx_paging(cfg, msg, &tp, nsei, ns_bvci);
682 break;
683 case BSSGP_PDUT_STATUS:
684 /* Some exception has occurred */
685 LOGP(DGPRS, LOGL_NOTICE,
Daniel Willmann3696dce2020-12-02 16:08:02 +0100686 "NSE(%05u/SGSN) BSSGP STATUS ", nsei);
Harald Welte173a1822020-12-03 15:36:59 +0100687 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_CAUSE, 1)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200688 LOGPC(DGPRS, LOGL_NOTICE, "\n");
689 goto err_mand_ie;
690 }
691 cause = *TLVP_VAL(&tp, BSSGP_IE_CAUSE);
692 LOGPC(DGPRS, LOGL_NOTICE,
693 "cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE),
694 bssgp_cause_str(cause));
Harald Welte173a1822020-12-03 15:36:59 +0100695 if (TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2)) {
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200696 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
Daniel Willmann3696dce2020-12-02 16:08:02 +0100697 LOGPC(DGPRS, LOGL_NOTICE, "BVCI=%05u\n", bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200698
699 if (cause == BSSGP_CAUSE_UNKNOWN_BVCI)
700 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
701 } else
702 LOGPC(DGPRS, LOGL_NOTICE, "\n");
703 break;
704 /* those only exist in the SGSN -> BSS direction */
705 case BSSGP_PDUT_SUSPEND_ACK:
706 case BSSGP_PDUT_SUSPEND_NACK:
707 case BSSGP_PDUT_RESUME_ACK:
708 case BSSGP_PDUT_RESUME_NACK:
709 /* RAI IE is mandatory */
Harald Welte173a1822020-12-03 15:36:59 +0100710 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_ROUTEING_AREA, 6))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200711 goto err_mand_ie;
Harald Welte560bdb32020-12-04 22:24:47 +0100712 bvc = gbproxy_bvc_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
713 if (!bvc)
714 goto err_no_bvc;
715 rc = gbprox_relay2peer(msg, bvc, ns_bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200716 break;
717 case BSSGP_PDUT_BVC_BLOCK_ACK:
718 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
Harald Welte173a1822020-12-03 15:36:59 +0100719 if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200720 goto err_mand_ie;
721 bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
722 if (bvci == 0) {
Daniel Willmann3696dce2020-12-02 16:08:02 +0100723 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP "
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200724 "%sBLOCK_ACK for signalling BVCI ?!?\n", nsei,
725 pdu_type == BSSGP_PDUT_BVC_UNBLOCK_ACK ? "UN":"");
Daniel Willmann65bfbaf2020-12-02 17:46:56 +0100726 /* TODO: should we send STATUS ? */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200727 rate_ctr_inc(&cfg->ctrg->
728 ctr[GBPROX_GLOB_CTR_INV_BVCI]);
729 } else {
730 /* Mark BVC as (un)blocked */
Harald Welte560bdb32020-12-04 22:24:47 +0100731 block_unblock_bvc(cfg, bvci, pdu_type);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200732 }
733 rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
734 break;
735 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
Harald Welte7479c4d2020-12-02 20:06:04 +0100736 case BSSGP_PDUT_OVERLOAD:
737 LOGP(DGPRS, LOGL_DEBUG,
738 "NSE(%05u/SGSN) BSSGP %s: broadcasting\n", nsei, bssgp_pdu_str(pdu_type));
Harald Welte560bdb32020-12-04 22:24:47 +0100739 /* broadcast to all BSS-side bvcs */
Harald Welted2fef952020-12-05 00:31:07 +0100740 hash_for_each(cfg->bss_nses, i, nse, list) {
Harald Welte7479c4d2020-12-02 20:06:04 +0100741 gbprox_relay2nse(msg, nse, 0);
742 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200743 break;
744 default:
Daniel Willmann3696dce2020-12-02 16:08:02 +0100745 LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP PDU type %s not supported\n", nsei,
746 bssgp_pdu_str(pdu_type));
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200747 rate_ctr_inc(&cfg->ctrg->
748 ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
749 rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
750 break;
751 }
752
753 msgb_free(msg);
754
755 return rc;
756err_mand_ie:
Daniel Willmann3696dce2020-12-02 16:08:02 +0100757 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) missing mandatory IE\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200758 nsei);
759 rate_ctr_inc(&cfg->ctrg->
760 ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
761 msgb_free(msg);
762 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, orig_msg);
Harald Welte560bdb32020-12-04 22:24:47 +0100763err_no_bvc:
764 LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) cannot find bvc based on RAI\n",
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200765 nsei);
766 rate_ctr_inc(&cfg->ctrg-> ctr[GBPROX_GLOB_CTR_INV_RAI]);
767 msgb_free(msg);
768 return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, orig_msg);
769}
770
Alexander Couzens951e1332020-09-22 13:21:46 +0200771int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200772{
773 int rc;
Alexander Couzens951e1332020-09-22 13:21:46 +0200774 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
775 struct gprs_ns2_inst *nsi = cfg->nsi;
776 struct osmo_gprs_ns2_prim nsp = {};
777
778 nsp.bvci = msgb_bvci(msg);
779 nsp.nsei = msgb_nsei(msg);
780
781 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA, PRIM_OP_REQUEST, msg);
782 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
783
784 return rc;
785}
786
787/* Main input function for Gb proxy */
788int gbprox_rcvmsg(void *ctx, struct msgb *msg)
789{
790 int rc;
791 uint16_t nsei = msgb_nsei(msg);
792 uint16_t ns_bvci = msgb_bvci(msg);
793 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
794
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200795 int remote_end_is_sgsn = gbproxy_is_sgsn_nsei(cfg, nsei);
796
Harald Welte278dd272020-12-06 13:35:24 +0100797 /* ensure minimum length to decode PCU type */
798 if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))
799 return bssgp_tx_status(BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);
800
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200801 /* Only BVCI=0 messages need special treatment */
802 if (ns_bvci == 0 || ns_bvci == 1) {
803 if (remote_end_is_sgsn)
804 rc = gbprox_rx_sig_from_sgsn(cfg, msg, nsei, ns_bvci);
805 else
806 rc = gbprox_rx_sig_from_bss(cfg, msg, nsei, ns_bvci);
807 } else {
808 /* All other BVCI are PTP */
809 if (remote_end_is_sgsn)
Alexander Couzens951e1332020-09-22 13:21:46 +0200810 rc = gbprox_rx_ptp_from_sgsn(cfg, msg, nsei,
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200811 ns_bvci);
812 else
Alexander Couzens951e1332020-09-22 13:21:46 +0200813 rc = gbprox_rx_ptp_from_bss(cfg, msg, nsei,
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200814 ns_bvci);
815 }
816
817 return rc;
818}
819
Alexander Couzens951e1332020-09-22 13:21:46 +0200820/* TODO: What about handling:
821 * NS_AFF_CAUSE_VC_FAILURE,
822 NS_AFF_CAUSE_VC_RECOVERY,
823 NS_AFF_CAUSE_FAILURE,
824 NS_AFF_CAUSE_RECOVERY,
825 osmocom own causes
826 NS_AFF_CAUSE_SNS_CONFIGURED,
827 NS_AFF_CAUSE_SNS_FAILURE,
828 */
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200829
Alexander Couzens951e1332020-09-22 13:21:46 +0200830void gprs_ns_prim_status_cb(struct gbproxy_config *cfg, struct osmo_gprs_ns2_prim *nsp)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200831{
Harald Welte560bdb32020-12-04 22:24:47 +0100832 /* 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 +0200833 * TODO: sgsn nsei available/unavailable
834 */
Harald Welte560bdb32020-12-04 22:24:47 +0100835 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200836
Alexander Couzens951e1332020-09-22 13:21:46 +0200837 switch (nsp->u.status.cause) {
838 case NS_AFF_CAUSE_SNS_FAILURE:
839 case NS_AFF_CAUSE_SNS_CONFIGURED:
840 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200841
Alexander Couzens951e1332020-09-22 13:21:46 +0200842 case NS_AFF_CAUSE_RECOVERY:
843 LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);
Harald Weltea0f70732020-12-05 17:50:23 +0100844 if (gbproxy_is_sgsn_nsei(cfg, nsp->nsei)) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200845 /* look-up or create the BTS context for this BVC */
846 struct bssgp_bvc_ctx *bctx = btsctx_by_bvci_nsei(nsp->bvci, nsp->nsei);
847 if (!bctx)
848 bctx = btsctx_alloc(nsp->bvci, nsp->nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200849
Alexander Couzens951e1332020-09-22 13:21:46 +0200850 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 +0200851 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200852 break;
853 case NS_AFF_CAUSE_FAILURE:
Harald Weltea0f70732020-12-05 17:50:23 +0100854 if (gbproxy_is_sgsn_nsei(cfg, nsp->nsei)) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200855 /* sgsn */
856 /* TODO: BSVC: block all PtP towards bss */
857 rate_ctr_inc(&cfg->ctrg->
858 ctr[GBPROX_GLOB_CTR_RESTART_RESET_SGSN]);
859 } else {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100860 /* bss became unavailable
861 * TODO: Block all BVC belonging to that NSE */
Harald Welte560bdb32020-12-04 22:24:47 +0100862 bvc = gbproxy_bvc_by_nsei(cfg, nsp->nsei);
863 if (!bvc) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200864 /* TODO: use primitive name + status cause name */
Harald Welte560bdb32020-12-04 22:24:47 +0100865 LOGP(DGPRS, LOGL_NOTICE, "Received ns2 primitive %d for unknown bvc NSEI=%u\n",
Alexander Couzens951e1332020-09-22 13:21:46 +0200866 nsp->u.status.cause, nsp->nsei);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200867 break;
868 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200869
Harald Welte560bdb32020-12-04 22:24:47 +0100870 if (!bvc->blocked)
Alexander Couzens951e1332020-09-22 13:21:46 +0200871 break;
872 bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, cfg->nsip_sgsn_nsei,
Harald Welte560bdb32020-12-04 22:24:47 +0100873 bvc->bvci, 0);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200874 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200875 LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);
876 break;
877 default:
Harald Welte95cf9fb2020-11-30 10:55:22 +0100878 LOGP(DPCU, LOGL_NOTICE, "NS: Unknown NS-STATUS.ind cause=%s from NS\n",
879 gprs_ns2_aff_cause_prim_str(nsp->u.status.cause));
Alexander Couzens951e1332020-09-22 13:21:46 +0200880 break;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200881 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200882}
883
Alexander Couzens951e1332020-09-22 13:21:46 +0200884/* called by the ns layer */
885int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
886{
887 struct osmo_gprs_ns2_prim *nsp;
888 struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;
Daniel Willmann8f407b12020-12-02 19:33:50 +0100889 uintptr_t bvci;
Alexander Couzens951e1332020-09-22 13:21:46 +0200890 int rc = 0;
891
892 if (oph->sap != SAP_NS)
893 return 0;
894
895 nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
896
897 if (oph->operation != PRIM_OP_INDICATION) {
Harald Welte95cf9fb2020-11-30 10:55:22 +0100898 LOGP(DPCU, LOGL_NOTICE, "NS: Unexpected primitive operation %s from NS\n",
899 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +0200900 return 0;
901 }
902
903 switch (oph->primitive) {
904 case PRIM_NS_UNIT_DATA:
Daniel Willmann8f407b12020-12-02 19:33:50 +0100905
Alexander Couzens951e1332020-09-22 13:21:46 +0200906 /* hand the message into the BSSGP implementation */
907 msgb_bssgph(oph->msg) = oph->msg->l3h;
908 msgb_bvci(oph->msg) = nsp->bvci;
909 msgb_nsei(oph->msg) = nsp->nsei;
Daniel Willmann8f407b12020-12-02 19:33:50 +0100910 bvci = nsp->bvci | BVC_LOG_CTX_FLAG;
Alexander Couzens951e1332020-09-22 13:21:46 +0200911
Daniel Willmann8f407b12020-12-02 19:33:50 +0100912 log_set_context(LOG_CTX_GB_BVC, (void *)bvci);
Alexander Couzens951e1332020-09-22 13:21:46 +0200913 rc = gbprox_rcvmsg(cfg, oph->msg);
Daniel Willmannb6550102020-11-04 17:32:56 +0100914 msgb_free(oph->msg);
Alexander Couzens951e1332020-09-22 13:21:46 +0200915 break;
916 case PRIM_NS_STATUS:
917 gprs_ns_prim_status_cb(cfg, nsp);
918 break;
919 default:
Harald Welte95cf9fb2020-11-30 10:55:22 +0100920 LOGP(DPCU, LOGL_NOTICE, "NS: Unknown prim %s %s from NS\n",
921 gprs_ns2_prim_str(oph->primitive),
922 get_value_string(osmo_prim_op_names, oph->operation));
Alexander Couzens951e1332020-09-22 13:21:46 +0200923 break;
924 }
925
926 return rc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200927}
928
929void gbprox_reset(struct gbproxy_config *cfg)
930{
Harald Welted2fef952020-12-05 00:31:07 +0100931 struct gbproxy_nse *nse;
932 struct hlist_node *ntmp;
Harald Welte8b4c7942020-12-05 10:14:49 +0100933 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200934
Harald Welted2fef952020-12-05 00:31:07 +0100935 hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
Harald Welte8b4c7942020-12-05 10:14:49 +0100936 struct gbproxy_bvc *bvc;
937 struct hlist_node *tmp;
938 hash_for_each_safe(nse->bvcs, j, tmp, bvc, list)
Harald Welte560bdb32020-12-04 22:24:47 +0100939 gbproxy_bvc_free(bvc);
Daniel Willmanne50550e2020-11-26 18:19:21 +0100940
941 gbproxy_nse_free(nse);
942 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200943
944 rate_ctr_group_free(cfg->ctrg);
945 gbproxy_init_config(cfg);
946}
947
948int gbproxy_init_config(struct gbproxy_config *cfg)
949{
950 struct timespec tp;
951
Harald Welted2fef952020-12-05 00:31:07 +0100952 hash_init(cfg->bss_nses);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200953 cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
954 if (!cfg->ctrg) {
955 LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
956 return -1;
957 }
958 osmo_clock_gettime(CLOCK_REALTIME, &tp);
959
960 return 0;
961}