Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 1 | /* Gb proxy peer handling */ |
| 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 <osmocom/sgsn/gb_proxy.h> |
| 24 | |
| 25 | #include <osmocom/sgsn/debug.h> |
| 26 | |
| 27 | #include <osmocom/gprs/protocol/gsm_08_18.h> |
Daniel Willmann | 8f407b1 | 2020-12-02 19:33:50 +0100 | [diff] [blame] | 28 | #include <osmocom/core/logging.h> |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 29 | #include <osmocom/core/rate_ctr.h> |
| 30 | #include <osmocom/core/stats.h> |
| 31 | #include <osmocom/core/talloc.h> |
| 32 | #include <osmocom/gsm/tlv.h> |
| 33 | |
| 34 | #include <string.h> |
| 35 | |
| 36 | extern void *tall_sgsn_ctx; |
| 37 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 38 | static const struct rate_ctr_desc bvc_ctr_description[] = { |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 39 | { "blocked", "BVC Block " }, |
| 40 | { "unblocked", "BVC Unblock " }, |
| 41 | { "dropped", "BVC blocked, dropped packet " }, |
| 42 | { "inv-nsei", "NSEI mismatch " }, |
| 43 | { "tx-err", "NS Transmission error " }, |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 44 | }; |
| 45 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 46 | osmo_static_assert(ARRAY_SIZE(bvc_ctr_description) == GBPROX_PEER_CTR_LAST, everything_described); |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 47 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 48 | static const struct rate_ctr_group_desc bvc_ctrg_desc = { |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 49 | .group_name_prefix = "gbproxy:peer", |
| 50 | .group_description = "GBProxy Peer Statistics", |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 51 | .num_ctr = ARRAY_SIZE(bvc_ctr_description), |
| 52 | .ctr_desc = bvc_ctr_description, |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 53 | .class_id = OSMO_STATS_CLASS_PEER, |
| 54 | }; |
| 55 | |
| 56 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 57 | /* Find the gbproxy_bvc by its BVCI. There can only be one match */ |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 58 | struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_nse *nse, uint16_t bvci) |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 59 | { |
Harald Welte | 8b4c794 | 2020-12-05 10:14:49 +0100 | [diff] [blame] | 60 | struct gbproxy_bvc *bvc; |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 61 | hash_for_each_possible(nse->bvcs, bvc, list, bvci) { |
| 62 | if (bvc->bvci == bvci) |
| 63 | return bvc; |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 64 | } |
| 65 | return NULL; |
| 66 | } |
| 67 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 68 | struct gbproxy_bvc *gbproxy_bvc_alloc(struct gbproxy_nse *nse, uint16_t bvci) |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 69 | { |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 70 | struct gbproxy_bvc *bvc; |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 71 | OSMO_ASSERT(nse); |
| 72 | struct gbproxy_config *cfg = nse->cfg; |
| 73 | OSMO_ASSERT(cfg); |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 74 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 75 | bvc = talloc_zero(tall_sgsn_ctx, struct gbproxy_bvc); |
| 76 | if (!bvc) |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 77 | return NULL; |
| 78 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 79 | bvc->bvci = bvci; |
Harald Welte | 4bd3e49 | 2020-12-07 12:06:52 +0100 | [diff] [blame] | 80 | bvc->ctrg = rate_ctr_group_alloc(bvc, &bvc_ctrg_desc, (nse->nsei << 16) | bvci); |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 81 | if (!bvc->ctrg) { |
| 82 | talloc_free(bvc); |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 83 | return NULL; |
| 84 | } |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 85 | bvc->nse = nse; |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 86 | |
Harald Welte | 8b4c794 | 2020-12-05 10:14:49 +0100 | [diff] [blame] | 87 | hash_add(nse->bvcs, &bvc->list, bvc->bvci); |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 88 | |
Harald Welte | cfc7e8e | 2020-12-07 12:03:10 +0100 | [diff] [blame] | 89 | LOGPBVC_CAT(bvc, DOBJ, LOGL_INFO, "BVC Created\n"); |
| 90 | |
| 91 | /* We leave allocating the bvc->fi to the caller, as the FSM details depend |
| 92 | * on the type of BVC (SIG/PTP) and role (SGSN/BSS) */ |
| 93 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 94 | return bvc; |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 95 | } |
| 96 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 97 | void gbproxy_bvc_free(struct gbproxy_bvc *bvc) |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 98 | { |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 99 | struct gbproxy_cell *cell; |
| 100 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 101 | if (!bvc) |
Daniel Willmann | f6a36cc | 2020-12-04 17:38:46 +0100 | [diff] [blame] | 102 | return; |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 103 | |
Harald Welte | cfc7e8e | 2020-12-07 12:03:10 +0100 | [diff] [blame] | 104 | LOGPBVC_CAT(bvc, DOBJ, LOGL_INFO, "BVC Destroying\n"); |
| 105 | |
Harald Welte | 8b4c794 | 2020-12-05 10:14:49 +0100 | [diff] [blame] | 106 | hash_del(&bvc->list); |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 107 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 108 | rate_ctr_group_free(bvc->ctrg); |
| 109 | bvc->ctrg = NULL; |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 110 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 111 | osmo_fsm_inst_free(bvc->fi); |
| 112 | |
| 113 | cell = bvc->cell; |
| 114 | if (cell) { |
| 115 | int i; |
| 116 | |
| 117 | if (cell->bss_bvc == bvc) |
| 118 | cell->bss_bvc = NULL; |
| 119 | |
| 120 | /* we could also be a SGSN-side BVC */ |
| 121 | for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) { |
| 122 | if (cell->sgsn_bvc[i] == bvc) |
| 123 | cell->sgsn_bvc[i] = NULL; |
| 124 | } |
| 125 | bvc->cell = NULL; |
| 126 | } |
| 127 | |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 128 | talloc_free(bvc); |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 129 | } |
| 130 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 131 | /*! remove BVCs on NSE specified by NSEI. |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 132 | * \param[in] cfg proxy in which we operate |
| 133 | * \param[in] nsei NS entity in which we should clean up |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 134 | * \param[in] bvci if 0: remove all PTP BVCs; if != 0: BVCI of the single BVC to clean up */ |
| 135 | int gbproxy_cleanup_bvcs(struct gbproxy_nse *nse, uint16_t bvci) |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 136 | { |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 137 | struct hlist_node *btmp; |
| 138 | struct gbproxy_bvc *bvc; |
| 139 | int j, counter = 0; |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 140 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 141 | if (!nse) |
| 142 | return 0; |
| 143 | |
| 144 | hash_for_each_safe(nse->bvcs, j, btmp, bvc, list) { |
| 145 | if (bvci && bvc->bvci != bvci) |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 146 | continue; |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 147 | if (bvci == 0 && bvc->bvci == 0) |
| 148 | continue; |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 149 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 150 | gbproxy_bvc_free(bvc); |
| 151 | counter += 1; |
Pau Espin Pedrol | 1ddefb1 | 2019-08-30 19:48:34 +0200 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | return counter; |
| 155 | } |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 156 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 157 | |
| 158 | /*********************************************************************** |
| 159 | * CELL |
| 160 | ***********************************************************************/ |
| 161 | |
| 162 | /* Allocate a new 'cell' object */ |
| 163 | struct gbproxy_cell *gbproxy_cell_alloc(struct gbproxy_config *cfg, uint16_t bvci) |
| 164 | { |
| 165 | struct gbproxy_cell *cell; |
| 166 | OSMO_ASSERT(cfg); |
| 167 | |
| 168 | cell = talloc_zero(cfg, struct gbproxy_cell); |
| 169 | if (!cell) |
| 170 | return NULL; |
| 171 | |
| 172 | cell->cfg = cfg; |
| 173 | cell->bvci = bvci; |
| 174 | |
| 175 | hash_add(cfg->cells, &cell->list, cell->bvci); |
| 176 | |
Harald Welte | cfc7e8e | 2020-12-07 12:03:10 +0100 | [diff] [blame] | 177 | LOGPCELL_CAT(cell, DOBJ, LOGL_INFO, "CELL Created\n"); |
| 178 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 179 | return cell; |
| 180 | } |
| 181 | |
| 182 | /* Find cell by BVCI */ |
| 183 | struct gbproxy_cell *gbproxy_cell_by_bvci(struct gbproxy_config *cfg, uint16_t bvci) |
| 184 | { |
| 185 | struct gbproxy_cell *cell; |
| 186 | |
| 187 | hash_for_each_possible(cfg->cells, cell, list, bvci) { |
| 188 | if (cell->bvci == bvci) |
| 189 | return cell; |
| 190 | } |
| 191 | return NULL; |
| 192 | } |
| 193 | |
| 194 | struct gbproxy_cell *gbproxy_cell_by_bvci_or_new(struct gbproxy_config *cfg, uint16_t bvci) |
| 195 | { |
| 196 | struct gbproxy_cell *cell; |
| 197 | OSMO_ASSERT(cfg); |
| 198 | |
| 199 | cell = gbproxy_cell_by_bvci(cfg, bvci); |
| 200 | if (!cell) |
| 201 | cell = gbproxy_cell_alloc(cfg, bvci); |
| 202 | |
| 203 | return cell; |
| 204 | } |
| 205 | |
| 206 | void gbproxy_cell_free(struct gbproxy_cell *cell) |
| 207 | { |
| 208 | unsigned int i; |
| 209 | |
| 210 | if (!cell) |
| 211 | return; |
| 212 | |
Harald Welte | cfc7e8e | 2020-12-07 12:03:10 +0100 | [diff] [blame] | 213 | LOGPCELL_CAT(cell, DOBJ, LOGL_INFO, "CELL Destroying\n"); |
| 214 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 215 | /* remove from cfg.cells */ |
| 216 | hash_del(&cell->list); |
| 217 | |
| 218 | /* remove back-pointers from the BSS side */ |
| 219 | if (cell->bss_bvc && cell->bss_bvc->cell) |
| 220 | cell->bss_bvc->cell = NULL; |
| 221 | |
| 222 | /* remove back-pointers from the SGSN side */ |
| 223 | for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) { |
| 224 | if (!cell->sgsn_bvc[i]) |
| 225 | continue; |
| 226 | if (cell->sgsn_bvc[i]->cell) |
| 227 | cell->sgsn_bvc[i]->cell = NULL; |
| 228 | } |
| 229 | |
| 230 | talloc_free(cell); |
| 231 | } |
| 232 | |
| 233 | bool gbproxy_cell_add_sgsn_bvc(struct gbproxy_cell *cell, struct gbproxy_bvc *bvc) |
| 234 | { |
| 235 | unsigned int i; |
| 236 | for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) { |
| 237 | if (!cell->sgsn_bvc[i]) { |
| 238 | cell->sgsn_bvc[i] = bvc; |
Harald Welte | cfc7e8e | 2020-12-07 12:03:10 +0100 | [diff] [blame] | 239 | LOGPCELL_CAT(cell, DOBJ, LOGL_DEBUG, "CELL linked to SGSN\n"); |
| 240 | LOGPBVC_CAT(bvc, DOBJ, LOGL_DEBUG, "BVC linked to CELL\n"); |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 241 | return true; |
| 242 | } |
| 243 | } |
| 244 | return false; |
| 245 | } |
| 246 | |
| 247 | /*********************************************************************** |
| 248 | * NSE - NS Entity |
| 249 | ***********************************************************************/ |
| 250 | |
| 251 | struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing) |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 252 | { |
| 253 | struct gbproxy_nse *nse; |
| 254 | OSMO_ASSERT(cfg); |
| 255 | |
| 256 | nse = talloc_zero(tall_sgsn_ctx, struct gbproxy_nse); |
| 257 | if (!nse) |
| 258 | return NULL; |
| 259 | |
| 260 | nse->nsei = nsei; |
| 261 | nse->cfg = cfg; |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 262 | nse->sgsn_facing = sgsn_facing; |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 263 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 264 | if (sgsn_facing) |
| 265 | hash_add(cfg->sgsn_nses, &nse->list, nsei); |
| 266 | else |
| 267 | hash_add(cfg->bss_nses, &nse->list, nsei); |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 268 | |
Harald Welte | 8b4c794 | 2020-12-05 10:14:49 +0100 | [diff] [blame] | 269 | hash_init(nse->bvcs); |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 270 | |
Harald Welte | cfc7e8e | 2020-12-07 12:03:10 +0100 | [diff] [blame] | 271 | LOGPNSE_CAT(nse, DOBJ, LOGL_INFO, "NSE Created\n"); |
| 272 | |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 273 | return nse; |
| 274 | } |
| 275 | |
| 276 | void gbproxy_nse_free(struct gbproxy_nse *nse) |
| 277 | { |
Harald Welte | 8b4c794 | 2020-12-05 10:14:49 +0100 | [diff] [blame] | 278 | struct gbproxy_bvc *bvc; |
| 279 | struct hlist_node *tmp; |
| 280 | int i; |
| 281 | |
Daniel Willmann | f6a36cc | 2020-12-04 17:38:46 +0100 | [diff] [blame] | 282 | if (!nse) |
| 283 | return; |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 284 | |
Harald Welte | cfc7e8e | 2020-12-07 12:03:10 +0100 | [diff] [blame] | 285 | LOGPNSE_CAT(nse, DOBJ, LOGL_INFO, "NSE Destroying\n"); |
| 286 | |
Harald Welte | d2fef95 | 2020-12-05 00:31:07 +0100 | [diff] [blame] | 287 | hash_del(&nse->list); |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 288 | |
Harald Welte | 8b4c794 | 2020-12-05 10:14:49 +0100 | [diff] [blame] | 289 | hash_for_each_safe(nse->bvcs, i, tmp, bvc, list) |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 290 | gbproxy_bvc_free(bvc); |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 291 | |
| 292 | talloc_free(nse); |
| 293 | } |
| 294 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 295 | struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags) |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 296 | { |
| 297 | struct gbproxy_nse *nse; |
| 298 | OSMO_ASSERT(cfg); |
| 299 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 300 | if (flags & NSE_F_SGSN) { |
| 301 | hash_for_each_possible(cfg->sgsn_nses, nse, list, nsei) { |
| 302 | if (nse->nsei == nsei) |
| 303 | return nse; |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | if (flags & NSE_F_BSS) { |
| 308 | hash_for_each_possible(cfg->bss_nses, nse, list, nsei) { |
| 309 | if (nse->nsei == nsei) |
| 310 | return nse; |
| 311 | } |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 312 | } |
| 313 | |
| 314 | return NULL; |
| 315 | } |
| 316 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 317 | struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing) |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 318 | { |
| 319 | struct gbproxy_nse *nse; |
| 320 | OSMO_ASSERT(cfg); |
| 321 | |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 322 | nse = gbproxy_nse_by_nsei(cfg, nsei, sgsn_facing ? NSE_F_SGSN : NSE_F_BSS); |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 323 | if (!nse) |
Harald Welte | e520964 | 2020-12-05 19:59:45 +0100 | [diff] [blame] | 324 | nse = gbproxy_nse_alloc(cfg, nsei, sgsn_facing); |
Daniel Willmann | e50550e | 2020-11-26 18:19:21 +0100 | [diff] [blame] | 325 | |
| 326 | return nse; |
Harald Welte | 560bdb3 | 2020-12-04 22:24:47 +0100 | [diff] [blame] | 327 | } |