blob: 3338911dbcb952e385b6e08fe0d9f45eb89f528b [file] [log] [blame]
Jacob Erlbeck9114bee2014-08-19 12:21:01 +02001/* GPRS Gb message parser */
2
3/* (C) 2014 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
Harald Welte6e688082014-08-24 17:38:18 +020021#include <osmocom/gsm/gsm48.h>
Harald Welte53373bc2016-04-20 17:11:43 +020022#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Harald Welte6e688082014-08-24 17:38:18 +020023
Pau Espin Pedrol749ca7c2022-12-22 19:49:37 +010024#include "gprs_gb_parse.h"
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020025
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020026#include <osmocom/sgsn/gprs_utils.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020027
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020028#include <osmocom/sgsn/debug.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020029
30#include <osmocom/gprs/gprs_bssgp.h>
31
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020032static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len,
33 struct gprs_gb_parse_context *parse_ctx)
34{
35 uint8_t *value;
36 size_t value_len;
37
38 parse_ctx->llc_msg_name = "ATTACH_REQ";
39
40 /* Skip MS network capability */
Harald Welte842674b2016-04-25 15:14:01 +020041 if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
Jacob Erlbeckc9cd15f2014-09-29 12:36:45 +020042 value_len < 1 || value_len > 8)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020043 /* invalid */
Jacob Erlbeckf349bae2014-09-29 12:45:36 +020044 return 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020045
46 /* Skip Attach type */
47 /* Skip Ciphering key sequence number */
48 /* Skip DRX parameter */
Stefan Sperling81c97ff2018-11-22 12:22:48 +010049 if (osmo_shift_v_fixed(&data, &data_len, 3, NULL) < 3)
50 return 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020051
52 /* Get Mobile identity */
Harald Welte842674b2016-04-25 15:14:01 +020053 if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020054 value_len < 5 || value_len > 8)
55 /* invalid */
56 return 0;
57
58 if (gprs_is_mi_tmsi(value, value_len)) {
Jacob Erlbeck49389172014-10-02 16:14:47 +020059 parse_ctx->ptmsi_enc = value + 1;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020060 } else if (gprs_is_mi_imsi(value, value_len)) {
61 parse_ctx->imsi = value;
62 parse_ctx->imsi_len = value_len;
63 }
64
Harald Welte842674b2016-04-25 15:14:01 +020065 if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020066 return 0;
67
68 parse_ctx->old_raid_enc = value;
69
70 return 1;
71}
72
73static int gprs_gb_parse_gmm_attach_ack(uint8_t *data, size_t data_len,
74 struct gprs_gb_parse_context *parse_ctx)
75{
76 uint8_t *value;
77 size_t value_len;
78
79 parse_ctx->llc_msg_name = "ATTACH_ACK";
80
81 /* Skip Attach result */
82 /* Skip Force to standby */
83 /* Skip Periodic RA update timer */
84 /* Skip Radio priority for SMS */
85 /* Skip Spare half octet */
Stefan Sperling81c97ff2018-11-22 12:22:48 +010086 if (osmo_shift_v_fixed(&data, &data_len, 3, NULL) < 3)
87 return 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020088
Harald Welte842674b2016-04-25 15:14:01 +020089 if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020090 return 0;
91
92 parse_ctx->raid_enc = value;
93
94 /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
Harald Welte842674b2016-04-25 15:14:01 +020095 osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020096
97 /* Skip Negotiated READY timer value (GPRS timer, opt, TV, length 2) */
Harald Welte842674b2016-04-25 15:14:01 +020098 osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020099
100 /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
Harald Welte842674b2016-04-25 15:14:01 +0200101 if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200102 &value, &value_len) > 0 &&
103 gprs_is_mi_tmsi(value, value_len))
Jacob Erlbeck49389172014-10-02 16:14:47 +0200104 parse_ctx->new_ptmsi_enc = value + 1;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200105 return 1;
106}
107
Jacob Erlbeck9c65c812014-09-22 10:42:05 +0200108static int gprs_gb_parse_gmm_attach_rej(uint8_t *data, size_t data_len,
109 struct gprs_gb_parse_context *parse_ctx)
110{
111 uint8_t *value;
112
113 parse_ctx->llc_msg_name = "ATTACH_REJ";
114
115 /* GMM cause */
Harald Welte842674b2016-04-25 15:14:01 +0200116 if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
Jacob Erlbeck9c65c812014-09-22 10:42:05 +0200117 return 0;
118
119 parse_ctx->invalidate_tlli = 1;
120
121 return 1;
122}
123
124
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200125static int gprs_gb_parse_gmm_detach_req(uint8_t *data, size_t data_len,
126 struct gprs_gb_parse_context *parse_ctx)
127{
128 uint8_t *value;
129 size_t value_len;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200130 int detach_type;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200131 int power_off;
132
133 parse_ctx->llc_msg_name = "DETACH_REQ";
134
135 /* Skip spare half octet */
136 /* Get Detach type */
Harald Welte842674b2016-04-25 15:14:01 +0200137 if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200138 /* invalid */
139 return 0;
140
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200141 detach_type = *value & 0x07;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200142 power_off = *value & 0x08 ? 1 : 0;
143
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200144 if (parse_ctx->to_bss) {
145 /* Network originated */
146 if (detach_type == GPRS_DET_T_MT_REATT_REQ)
147 parse_ctx->await_reattach = 1;
148 } else {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200149 /* Mobile originated */
150
151 if (power_off)
152 parse_ctx->invalidate_tlli = 1;
153
154 /* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */
Harald Welte842674b2016-04-25 15:14:01 +0200155 if (osmo_match_shift_tlv(&data, &data_len,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200156 GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0)
157 {
158 if (gprs_is_mi_tmsi(value, value_len))
Jacob Erlbeck49389172014-10-02 16:14:47 +0200159 parse_ctx->ptmsi_enc = value + 1;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200160 }
161 }
162
163 return 1;
164}
165
166static int gprs_gb_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len,
167 struct gprs_gb_parse_context *parse_ctx)
168{
169 uint8_t *value;
170
171 parse_ctx->llc_msg_name = "RA_UPD_REQ";
172
173 /* Skip Update type */
174 /* Skip GPRS ciphering key sequence number */
Stefan Sperling81c97ff2018-11-22 12:22:48 +0100175 if (osmo_shift_v_fixed(&data, &data_len, 1, NULL) < 1)
176 return 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200177
Harald Welte842674b2016-04-25 15:14:01 +0200178 if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200179 return 0;
180
181 parse_ctx->old_raid_enc = value;
182
183 return 1;
184}
185
Jacob Erlbeck85e5c8f2014-09-16 12:16:58 +0200186static int gprs_gb_parse_gmm_ra_upd_rej(uint8_t *data, size_t data_len,
187 struct gprs_gb_parse_context *parse_ctx)
188{
189 uint8_t *value;
190 uint8_t cause;
191 int force_standby;
192
193 parse_ctx->llc_msg_name = "RA_UPD_REJ";
194
195 /* GMM cause */
Harald Welte842674b2016-04-25 15:14:01 +0200196 if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
Jacob Erlbeck85e5c8f2014-09-16 12:16:58 +0200197 return 0;
198
199 cause = value[0];
200
201 /* Force to standby, 1/2 */
202 /* spare bits, 1/2 */
Harald Welte842674b2016-04-25 15:14:01 +0200203 if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
Jacob Erlbeck85e5c8f2014-09-16 12:16:58 +0200204 return 0;
205
206 force_standby = (value[0] & 0x07) == 0x01;
207
208 if (cause == GMM_CAUSE_IMPL_DETACHED && !force_standby)
209 parse_ctx->await_reattach = 1;
210
211 parse_ctx->invalidate_tlli = 1;
212
213 return 1;
214}
215
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200216static int gprs_gb_parse_gmm_ra_upd_ack(uint8_t *data, size_t data_len,
217 struct gprs_gb_parse_context *parse_ctx)
218{
219 uint8_t *value;
220 size_t value_len;
221
222 parse_ctx->llc_msg_name = "RA_UPD_ACK";
223
224 /* Skip Force to standby */
225 /* Skip Update result */
226 /* Skip Periodic RA update timer */
Stefan Sperling81c97ff2018-11-22 12:22:48 +0100227 if (osmo_shift_v_fixed(&data, &data_len, 2, NULL) < 2)
228 return 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200229
Harald Welte842674b2016-04-25 15:14:01 +0200230 if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200231 return 0;
232
233 parse_ctx->raid_enc = value;
234
235 /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
Harald Welte842674b2016-04-25 15:14:01 +0200236 osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200237
238 /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
Harald Welte842674b2016-04-25 15:14:01 +0200239 if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200240 &value, &value_len) > 0 &&
241 gprs_is_mi_tmsi(value, value_len))
Jacob Erlbeck49389172014-10-02 16:14:47 +0200242 parse_ctx->new_ptmsi_enc = value + 1;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200243
244 return 1;
245}
246
247static int gprs_gb_parse_gmm_ptmsi_reall_cmd(uint8_t *data, size_t data_len,
248 struct gprs_gb_parse_context *parse_ctx)
249{
250 uint8_t *value;
251 size_t value_len;
252
253 parse_ctx->llc_msg_name = "PTMSI_REALL_CMD";
254
255 LOGP(DLLC, LOGL_NOTICE,
256 "Got P-TMSI Reallocation Command which is not covered by unit tests yet.\n");
257
258 /* Allocated P-TMSI */
Harald Welte842674b2016-04-25 15:14:01 +0200259 if (osmo_shift_lv(&data, &data_len, &value, &value_len) > 0 &&
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200260 gprs_is_mi_tmsi(value, value_len))
Jacob Erlbeck49389172014-10-02 16:14:47 +0200261 parse_ctx->new_ptmsi_enc = value + 1;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200262
Harald Welte842674b2016-04-25 15:14:01 +0200263 if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200264 return 0;
265
266 parse_ctx->raid_enc = value;
267
268 return 1;
269}
270
271static int gprs_gb_parse_gmm_id_resp(uint8_t *data, size_t data_len,
272 struct gprs_gb_parse_context *parse_ctx)
273{
274 uint8_t *value;
275 size_t value_len;
276
277 parse_ctx->llc_msg_name = "ID_RESP";
278
279 /* Mobile identity, Mobile identity 10.5.1.4, M LV 2-10 */
Harald Welte842674b2016-04-25 15:14:01 +0200280 if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200281 value_len < 1 || value_len > 9)
282 /* invalid */
283 return 0;
284
285 if (gprs_is_mi_tmsi(value, value_len)) {
Jacob Erlbeck49389172014-10-02 16:14:47 +0200286 parse_ctx->ptmsi_enc = value + 1;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200287 } else if (gprs_is_mi_imsi(value, value_len)) {
288 parse_ctx->imsi = value;
289 parse_ctx->imsi_len = value_len;
290 }
291
292 return 1;
293}
294
295static int gprs_gb_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len,
296 struct gprs_gb_parse_context *parse_ctx)
297{
298 ssize_t old_len;
299 uint8_t *value;
300 size_t value_len;
301
302 parse_ctx->llc_msg_name = "ACT_PDP_REQ";
303
304 /* Skip Requested NSAPI */
305 /* Skip Requested LLC SAPI */
Stefan Sperling81c97ff2018-11-22 12:22:48 +0100306 if (osmo_shift_v_fixed(&data, &data_len, 2, NULL) < 2)
307 return 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200308
309 /* Skip Requested QoS (support 04.08 and 24.008) */
Harald Welte842674b2016-04-25 15:14:01 +0200310 if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200311 value_len < 4 || value_len > 14)
312 /* invalid */
Jacob Erlbeckf349bae2014-09-29 12:45:36 +0200313 return 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200314
315 /* Skip Requested PDP address */
Harald Welte842674b2016-04-25 15:14:01 +0200316 if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200317 value_len < 2 || value_len > 18)
318 /* invalid */
319 return 0;
320
321 /* Access point name */
Harald Welte842674b2016-04-25 15:14:01 +0200322 old_len = osmo_match_shift_tlv(&data, &data_len,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200323 GSM48_IE_GSM_APN, &value, &value_len);
324
325 if (old_len > 0 && value_len >=1 && value_len <= 100) {
326 parse_ctx->apn_ie = data - old_len;
327 parse_ctx->apn_ie_len = old_len;
328 }
329
330 return 1;
331}
332
333int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
334 struct gprs_gb_parse_context *parse_ctx)
335{
336 struct gsm48_hdr *g48h;
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100337 uint8_t pdisc;
338 uint8_t msg_type;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200339
Harald Welte842674b2016-04-25 15:14:01 +0200340 if (osmo_shift_v_fixed(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200341 return 0;
342
343 parse_ctx->g48_hdr = g48h;
344
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100345 pdisc = gsm48_hdr_pdisc(g48h);
346 if (pdisc != GSM48_PDISC_MM_GPRS && pdisc != GSM48_PDISC_SM_GPRS)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200347 return 1;
348
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100349 msg_type = gsm48_hdr_msg_type(g48h);
350 switch (msg_type) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200351 case GSM48_MT_GMM_ATTACH_REQ:
352 return gprs_gb_parse_gmm_attach_req(data, data_len, parse_ctx);
353
Jacob Erlbeck9c65c812014-09-22 10:42:05 +0200354 case GSM48_MT_GMM_ATTACH_REJ:
355 return gprs_gb_parse_gmm_attach_rej(data, data_len, parse_ctx);
356
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200357 case GSM48_MT_GMM_ATTACH_ACK:
358 return gprs_gb_parse_gmm_attach_ack(data, data_len, parse_ctx);
359
360 case GSM48_MT_GMM_RA_UPD_REQ:
361 return gprs_gb_parse_gmm_ra_upd_req(data, data_len, parse_ctx);
362
Jacob Erlbeck85e5c8f2014-09-16 12:16:58 +0200363 case GSM48_MT_GMM_RA_UPD_REJ:
364 return gprs_gb_parse_gmm_ra_upd_rej(data, data_len, parse_ctx);
365
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200366 case GSM48_MT_GMM_RA_UPD_ACK:
367 return gprs_gb_parse_gmm_ra_upd_ack(data, data_len, parse_ctx);
368
369 case GSM48_MT_GMM_PTMSI_REALL_CMD:
370 return gprs_gb_parse_gmm_ptmsi_reall_cmd(data, data_len, parse_ctx);
371
372 case GSM48_MT_GSM_ACT_PDP_REQ:
373 return gprs_gb_parse_gsm_act_pdp_req(data, data_len, parse_ctx);
374
375 case GSM48_MT_GMM_ID_RESP:
376 return gprs_gb_parse_gmm_id_resp(data, data_len, parse_ctx);
377
378 case GSM48_MT_GMM_DETACH_REQ:
379 return gprs_gb_parse_gmm_detach_req(data, data_len, parse_ctx);
380
381 case GSM48_MT_GMM_DETACH_ACK:
382 parse_ctx->llc_msg_name = "DETACH_ACK";
383 parse_ctx->invalidate_tlli = 1;
384 break;
385
Alexander Couzens6c0586a2019-04-14 05:36:00 +0200386 case GSM48_MT_GSM_DEACT_PDP_REQ:
387 parse_ctx->llc_msg_name = "DEACT_PDP_REQ";
388 break;
389
390 case GSM48_MT_GSM_DEACT_PDP_ACK:
391 parse_ctx->llc_msg_name = "DEACT_PDP_ACK";
392 break;
393
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200394 default:
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100395 LOGP(DLLC, LOGL_NOTICE,
Max7b5dbc22017-05-05 13:24:03 +0200396 "Unhandled GSM 04.08 message type %s for protocol discriminator %s.\n",
397 get_value_string(gprs_msgt_gmm_names, msg_type), get_value_string(gsm48_pdisc_names, pdisc));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200398 break;
399 };
400
401 return 1;
402}
403
404int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
405 struct gprs_gb_parse_context *parse_ctx)
406{
407 struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
408 int rc;
409 int fcs;
410
411 /* parse LLC */
412 rc = gprs_llc_hdr_parse(ghp, llc, llc_len);
Max549ebc72016-11-18 14:07:04 +0100413 gprs_llc_hdr_dump(ghp, NULL);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200414 if (rc != 0) {
415 LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n");
416 return 0;
417 }
418
419 fcs = gprs_llc_fcs(llc, ghp->crc_length);
420 LOGP(DLLC, LOGL_DEBUG, "Got LLC message, CRC: %06x (computed %06x)\n",
421 ghp->fcs, fcs);
422
423 if (!ghp->data)
424 return 0;
425
426 if (ghp->sapi != GPRS_SAPI_GMM)
427 return 1;
428
429 if (ghp->cmd != GPRS_LLC_UI)
430 return 1;
431
432 if (ghp->is_encrypted) {
433 parse_ctx->need_decryption = 1;
434 return 0;
435 }
436
437 return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx);
438}
439
Harald Welte952fbf22020-11-18 11:57:42 +0100440/*! Determine the TLLI from the given BSSGP message.
441 * \param[in] bssgp pointer to start of BSSGP header
442 * \param[in] bssgp_len length of BSSGP message in octets
443 * \param[out] tlli TLLI (if any) in host byte order
444 * \returns 1 if TLLI found; 0 if none found; negative on parse error */
445int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli)
446{
447 const struct bssgp_normal_hdr *bgph;
448 uint8_t pdu_type;
449
450 if (bssgp_len < sizeof(struct bssgp_normal_hdr))
451 return -EINVAL;
452
453 bgph = (struct bssgp_normal_hdr *)bssgp;
454 pdu_type = bgph->pdu_type;
455
456 if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
457 pdu_type == BSSGP_PDUT_DL_UNITDATA) {
458 const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *)bssgp;
459 if (bssgp_len < sizeof(struct bssgp_ud_hdr))
460 return -EINVAL;
461 *tlli = osmo_load32be((const uint8_t *)&budh->tlli);
462 return 1;
463 } else {
464 const uint8_t *data = bgph->data;
465 size_t data_len = bssgp_len - sizeof(*bgph);
466 struct tlv_parsed tp;
467
468 if (bssgp_tlv_parse(&tp, data, data_len) < 0)
469 return -EINVAL;
470
471 if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
472 *tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
473 return 1;
474 }
475 }
476
477 /* No TLLI present in message */
478 return 0;
479}
480
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200481int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
482 struct gprs_gb_parse_context *parse_ctx)
483{
484 struct bssgp_normal_hdr *bgph;
485 struct bssgp_ud_hdr *budh = NULL;
486 struct tlv_parsed *tp = &parse_ctx->bssgp_tp;
487 uint8_t pdu_type;
488 uint8_t *data;
489 size_t data_len;
490 int rc;
491
492 if (bssgp_len < sizeof(struct bssgp_normal_hdr))
493 return 0;
494
495 bgph = (struct bssgp_normal_hdr *)bssgp;
496 pdu_type = bgph->pdu_type;
497
498 if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
499 pdu_type == BSSGP_PDUT_DL_UNITDATA) {
500 if (bssgp_len < sizeof(struct bssgp_ud_hdr))
501 return 0;
502 budh = (struct bssgp_ud_hdr *)bssgp;
503 bgph = NULL;
504 data = budh->data;
505 data_len = bssgp_len - sizeof(*budh);
506 } else {
507 data = bgph->data;
508 data_len = bssgp_len - sizeof(*bgph);
509 }
510
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200511 parse_ctx->pdu_type = pdu_type;
512 parse_ctx->bud_hdr = budh;
513 parse_ctx->bgp_hdr = bgph;
514 parse_ctx->bssgp_data = data;
515 parse_ctx->bssgp_data_len = data_len;
516
Jacob Erlbeck9b071352014-10-09 12:04:56 +0200517 if (bssgp_tlv_parse(tp, data, data_len) < 0)
518 return 0;
519
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200520 if (budh)
521 parse_ctx->tlli_enc = (uint8_t *)&budh->tlli;
522
523 if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA))
524 parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
525
526 if (TLVP_PRESENT(tp, BSSGP_IE_CELL_ID))
527 parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_CELL_ID);
528
529 if (TLVP_PRESENT(tp, BSSGP_IE_IMSI)) {
530 parse_ctx->imsi = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_IMSI);
531 parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
532 }
533
Jacob Erlbeck4b663ac2014-08-21 15:07:11 +0200534 if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) {
535 if (parse_ctx->tlli_enc)
536 /* This is TLLI old, don't confuse it with TLLI current */
537 parse_ctx->old_tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
538 else
539 parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
540 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200541
542 if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS)
Jacob Erlbeckc37ef6c2014-09-30 13:49:43 +0200543 parse_ctx->bssgp_ptmsi_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TMSI);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200544
545 if (TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) {
546 uint8_t *llc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
547 size_t llc_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
548
549 rc = gprs_gb_parse_llc(llc, llc_len, parse_ctx);
550 if (!rc)
551 return 0;
552
553 parse_ctx->llc = llc;
554 parse_ctx->llc_len = llc_len;
555 }
556
557 if (parse_ctx->tlli_enc) {
558 uint32_t tmp_tlli;
559 memcpy(&tmp_tlli, parse_ctx->tlli_enc, sizeof(tmp_tlli));
560 parse_ctx->tlli = ntohl(tmp_tlli);
561 }
562
Jacob Erlbeck948c07f2014-09-11 15:22:18 +0200563 if (parse_ctx->bssgp_raid_enc && parse_ctx->old_raid_enc &&
564 memcmp(parse_ctx->bssgp_raid_enc, parse_ctx->old_raid_enc, 6) != 0)
565 parse_ctx->old_raid_is_foreign = 1;
566
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200567 return 1;
568}
569
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200570void gprs_gb_log_parse_context(int log_level,
571 struct gprs_gb_parse_context *parse_ctx,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200572 const char *default_msg_name)
573{
Jacob Erlbeck9b071352014-10-09 12:04:56 +0200574 const char *msg_name;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200575 const char *sep = "";
576
577 if (!parse_ctx->tlli_enc &&
578 !parse_ctx->ptmsi_enc &&
579 !parse_ctx->new_ptmsi_enc &&
Jacob Erlbeckc37ef6c2014-09-30 13:49:43 +0200580 !parse_ctx->bssgp_ptmsi_enc &&
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200581 !parse_ctx->imsi)
582 return;
583
Jacob Erlbeck9b071352014-10-09 12:04:56 +0200584 msg_name = gprs_gb_message_name(parse_ctx, default_msg_name);
585
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200586 if (parse_ctx->llc_msg_name)
587 msg_name = parse_ctx->llc_msg_name;
588
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200589 LOGP(DGPRS, log_level, "%s: Got", msg_name);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200590
591 if (parse_ctx->tlli_enc) {
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200592 LOGPC(DGPRS, log_level, "%s TLLI %08x", sep, parse_ctx->tlli);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200593 sep = ",";
594 }
595
Jacob Erlbeck4b663ac2014-08-21 15:07:11 +0200596 if (parse_ctx->old_tlli_enc) {
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200597 LOGPC(DGPRS, log_level, "%s old TLLI %02x%02x%02x%02x", sep,
Jacob Erlbeck4b663ac2014-08-21 15:07:11 +0200598 parse_ctx->old_tlli_enc[0],
599 parse_ctx->old_tlli_enc[1],
600 parse_ctx->old_tlli_enc[2],
601 parse_ctx->old_tlli_enc[3]);
602 sep = ",";
603 }
604
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200605 if (parse_ctx->bssgp_raid_enc) {
606 struct gprs_ra_id raid;
607 gsm48_parse_ra(&raid, parse_ctx->bssgp_raid_enc);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100608 LOGPC(DGPRS, log_level, "%s BSSGP RAID %s", sep, osmo_rai_name(&raid));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200609 sep = ",";
610 }
611
612 if (parse_ctx->raid_enc) {
613 struct gprs_ra_id raid;
614 gsm48_parse_ra(&raid, parse_ctx->raid_enc);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100615 LOGPC(DGPRS, log_level, "%s RAID %s", sep, osmo_rai_name(&raid));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200616 sep = ",";
617 }
618
619 if (parse_ctx->old_raid_enc) {
620 struct gprs_ra_id raid;
621 gsm48_parse_ra(&raid, parse_ctx->old_raid_enc);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100622 LOGPC(DGPRS, log_level, "%s old RAID %s", sep, osmo_rai_name(&raid));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200623 sep = ",";
624 }
625
Jacob Erlbeckc37ef6c2014-09-30 13:49:43 +0200626 if (parse_ctx->bssgp_ptmsi_enc) {
627 uint32_t ptmsi = GSM_RESERVED_TMSI;
628 gprs_parse_tmsi(parse_ctx->bssgp_ptmsi_enc, &ptmsi);
629 LOGPC(DGPRS, log_level, "%s BSSGP PTMSI %08x", sep, ptmsi);
630 sep = ",";
631 }
632
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200633 if (parse_ctx->ptmsi_enc) {
634 uint32_t ptmsi = GSM_RESERVED_TMSI;
Jacob Erlbeck49389172014-10-02 16:14:47 +0200635 gprs_parse_tmsi(parse_ctx->ptmsi_enc, &ptmsi);
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200636 LOGPC(DGPRS, log_level, "%s PTMSI %08x", sep, ptmsi);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200637 sep = ",";
638 }
639
640 if (parse_ctx->new_ptmsi_enc) {
641 uint32_t new_ptmsi = GSM_RESERVED_TMSI;
Jacob Erlbeck49389172014-10-02 16:14:47 +0200642 gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200643 LOGPC(DGPRS, log_level, "%s new PTMSI %08x", sep, new_ptmsi);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200644 sep = ",";
645 }
646
647 if (parse_ctx->imsi) {
Neels Hofmeyrb26a5a82020-05-29 16:53:23 +0200648 struct osmo_mobile_identity mi;
649 if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false) == 0
650 && mi.type == GSM_MI_TYPE_IMSI) {
651 LOGPC(DGPRS, log_level, "%s IMSI %s", sep, mi.imsi);
652 sep = ",";
653 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200654 }
655 if (parse_ctx->invalidate_tlli) {
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200656 LOGPC(DGPRS, log_level, "%s invalidate", sep);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200657 sep = ",";
658 }
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200659 if (parse_ctx->await_reattach) {
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200660 LOGPC(DGPRS, log_level, "%s re-attach", sep);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200661 sep = ",";
662 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200663
Jacob Erlbeck1c407aa2014-10-09 12:16:17 +0200664 LOGPC(DGPRS, log_level, "\n");
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200665}
666
Jacob Erlbeck9b071352014-10-09 12:04:56 +0200667const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
668 const char *default_msg_name)
669{
670 if (parse_ctx->llc_msg_name)
671 return parse_ctx->llc_msg_name;
672
673 if (parse_ctx->g48_hdr)
674 return "GMM";
675
676 if (parse_ctx->llc)
677 return "LLC";
678
679 if (parse_ctx->bud_hdr)
680 return "BSSGP-UNITDATA";
681
682 if (parse_ctx->bgp_hdr)
683 return "BSSGP";
684
685 return "unknown";
686}