4e45a4276157e65185c3fde816d8a332892bbaea
[osmocom-bb.git] / src / host / layer23 / src / misc / app_ccch_scan.c
1 /* CCCH passive sniffer */
2 /* (C) 2010-2011 by Holger Hans Peter Freyther
3  * (C) 2010 by Harald Welte <laforge@gnumonks.org>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24 #include <errno.h>
25 #include <stdio.h>
26
27 #include <osmocore/msgb.h>
28 #include <osmocore/rsl.h>
29 #include <osmocore/tlv.h>
30 #include <osmocore/gsm48_ie.h>
31 #include <osmocore/gsm48.h>
32 #include <osmocore/signal.h>
33 #include <osmocore/protocol/gsm_04_08.h>
34
35 #include <osmocom/bb/common/logging.h>
36 #include <osmocom/bb/common/lapdm.h>
37 #include <osmocom/bb/misc/rslms.h>
38 #include <osmocom/bb/misc/layer3.h>
39 #include <osmocom/bb/common/osmocom_data.h>
40 #include <osmocom/bb/common/l1ctl.h>
41 #include <osmocom/bb/common/l23_app.h>
42
43 static struct {
44         int has_si1;
45         int ccch_mode;
46         int ccch_enabled;
47         int rach_count;
48         struct gsm_sysinfo_freq cell_arfcns[1024];
49 } app_state;
50
51
52 static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
53 {
54         struct gsm48_system_information_type_header *si_hdr;
55         si_hdr = (struct gsm48_system_information_type_header *) data;
56
57         /* GSM 05.02 ยง6.3.1.3 Mapping of BCCH data */
58         switch (si_hdr->system_information) {
59         case GSM48_MT_RR_SYSINFO_1:
60 #ifdef BCCH_TC_CHECK
61                 if (tc != 0)
62                         LOGP(DRR, LOGL_ERROR, "SI1 on the wrong TC: %d\n", tc);
63 #endif
64                 if (!app_state.has_si1) {
65                         struct gsm48_system_information_type_1 *si1 =
66                                 (struct gsm48_system_information_type_1 *)data;
67
68                         gsm48_decode_freq_list(app_state.cell_arfcns,
69                                                si1->cell_channel_description,
70                                                sizeof(si1->cell_channel_description),
71                                                0xff, 0x01);
72
73                         app_state.has_si1 = 1;
74                         LOGP(DRR, LOGL_ERROR, "SI1 received.\n");
75                 }
76                 break;
77         case GSM48_MT_RR_SYSINFO_2:
78 #ifdef BCCH_TC_CHECK
79                 if (tc != 1)
80                         LOGP(DRR, LOGL_ERROR, "SI2 on the wrong TC: %d\n", tc);
81 #endif
82                 break;
83         case GSM48_MT_RR_SYSINFO_3:
84 #ifdef BCCH_TC_CHECK
85                 if (tc != 2 && tc != 6)
86                         LOGP(DRR, LOGL_ERROR, "SI3 on the wrong TC: %d\n", tc);
87 #endif
88                 if (app_state.ccch_mode == CCCH_MODE_NONE) {
89                         struct gsm48_system_information_type_3 *si3 =
90                                 (struct gsm48_system_information_type_3 *)data;
91
92                         if (si3->control_channel_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
93                                 app_state.ccch_mode = CCCH_MODE_COMBINED;
94                         else
95                                 app_state.ccch_mode = CCCH_MODE_NON_COMBINED;
96
97                         l1ctl_tx_ccch_mode_req(ms, app_state.ccch_mode);
98                 }
99                 break;
100         case GSM48_MT_RR_SYSINFO_4:
101 #ifdef BCCH_TC_CHECK
102                 if (tc != 3 && tc != 7)
103                         LOGP(DRR, LOGL_ERROR, "SI4 on the wrong TC: %d\n", tc);
104 #endif
105                 break;
106         case GSM48_MT_RR_SYSINFO_5:
107                 break;
108         case GSM48_MT_RR_SYSINFO_6:
109                 break;
110         case GSM48_MT_RR_SYSINFO_7:
111 #ifdef BCCH_TC_CHECK
112                 if (tc != 7)
113                         LOGP(DRR, LOGL_ERROR, "SI7 on the wrong TC: %d\n", tc);
114 #endif
115                 break;
116         case GSM48_MT_RR_SYSINFO_8:
117 #ifdef BCCH_TC_CHECK
118                 if (tc != 3)
119                         LOGP(DRR, LOGL_ERROR, "SI8 on the wrong TC: %d\n", tc);
120 #endif
121                 break;
122         case GSM48_MT_RR_SYSINFO_9:
123 #ifdef BCCH_TC_CHECK
124                 if (tc != 4)
125                         LOGP(DRR, LOGL_ERROR, "SI9 on the wrong TC: %d\n", tc);
126 #endif
127                 break;
128         case GSM48_MT_RR_SYSINFO_13:
129 #ifdef BCCH_TC_CHECK
130                 if (tc != 4 && tc != 0)
131                         LOGP(DRR, LOGL_ERROR, "SI13 on the wrong TC: %d\n", tc);
132 #endif
133                 break;
134         case GSM48_MT_RR_SYSINFO_16:
135 #ifdef BCCH_TC_CHECK
136                 if (tc != 6)
137                         LOGP(DRR, LOGL_ERROR, "SI16 on the wrong TC: %d\n", tc);
138 #endif
139                 break;
140         case GSM48_MT_RR_SYSINFO_17:
141 #ifdef BCCH_TC_CHECK
142                 if (tc != 2)
143                         LOGP(DRR, LOGL_ERROR, "SI17 on the wrong TC: %d\n", tc);
144 #endif
145                 break;
146         case GSM48_MT_RR_SYSINFO_2bis:
147 #ifdef BCCH_TC_CHECK
148                 if (tc != 5)
149                         LOGP(DRR, LOGL_ERROR, "SI2bis on the wrong TC: %d\n", tc);
150 #endif
151                 break;
152         case GSM48_MT_RR_SYSINFO_2ter:
153 #ifdef BCCH_TC_CHECK
154                 if (tc != 5 && tc != 4)
155                         LOGP(DRR, LOGL_ERROR, "SI2ter on the wrong TC: %d\n", tc);
156 #endif
157                 break;
158         case GSM48_MT_RR_SYSINFO_5bis:
159                 break;
160         case GSM48_MT_RR_SYSINFO_5ter:
161                 break;
162         default:
163                 fprintf(stderr, "\tUnknown SI");
164                 break;
165         };
166 }
167
168
169 /**
170  * This method used to send a l1ctl_tx_dm_est_req_h0 or
171  * a l1ctl_tx_dm_est_req_h1 to the layer1 to follow this
172  * assignment. The code has been removed.
173  */
174 static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
175 {
176         struct gsm48_imm_ass *ia = msgb_l3(msg);
177         uint8_t ch_type, ch_subch, ch_ts;
178
179         /* Discard packet TBF assignement */
180         if (ia->page_mode & 0xf0)
181                 return 0;
182
183         /* FIXME: compare RA and GSM time with when we sent RACH req */
184
185         rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);
186
187         if (!ia->chan_desc.h0.h) {
188                 /* Non-hopping */
189                 uint16_t arfcn;
190
191                 arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
192
193                 LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
194                         "ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
195                         ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
196                         ia->chan_desc.h0.tsc);
197
198         } else {
199                 /* Hopping */
200                 uint8_t maio, hsn, ma_len;
201                 uint16_t ma[64], arfcn;
202                 int i, j, k;
203
204                 hsn = ia->chan_desc.h1.hsn;
205                 maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
206
207                 LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
208                         "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
209                         ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
210                         ia->chan_desc.h1.tsc);
211
212                 /* decode mobile allocation */
213                 ma_len = 0;
214                 for (i=1, j=0; i<=1024; i++) {
215                         arfcn = i & 1023;
216                         if (app_state.cell_arfcns[arfcn].mask & 0x01) {
217                                 k = ia->mob_alloc_len - (j>>3) - 1;
218                                 if (ia->mob_alloc[k] & (1 << (j&7))) {
219                                         ma[ma_len++] = arfcn;
220                                 }
221                                 j++;
222                         }
223                 }
224         }
225
226         LOGPC(DRR, LOGL_NOTICE, "\n");
227         return 0;
228 }
229
230 static const char *pag_print_mode(int mode)
231 {
232         switch (mode) {
233         case 0:
234                 return "Normal paging";
235         case 1:
236                 return "Extended paging";
237         case 2:
238                 return "Paging reorganization";
239         case 3:
240                 return "Same as before";
241         default:
242                 return "invalid";
243         }
244 }
245
246 static char *chan_need(int need)
247 {
248         switch (need) {
249         case 0:
250                 return "any";
251         case 1:
252                 return "sdch";
253         case 2:
254                 return "tch/f";
255         case 3:
256                 return "tch/h";
257         default:
258                 return "invalid";
259         }
260 }
261
262 static char *mi_type_to_string(int type)
263 {
264         switch (type) {
265         case GSM_MI_TYPE_NONE:
266                 return "none";
267         case GSM_MI_TYPE_IMSI:
268                 return "imsi";
269         case GSM_MI_TYPE_IMEI:
270                 return "imei";
271         case GSM_MI_TYPE_IMEISV:
272                 return "imeisv";
273         case GSM_MI_TYPE_TMSI:
274                 return "tmsi";
275         default:
276                 return "invalid";
277         }
278 }
279
280 /**
281  * This can contain two MIs. The size checking is a bit of a mess.
282  */
283 static int gsm48_rx_paging_p1(struct msgb *msg, struct osmocom_ms *ms)
284 {
285         struct gsm48_paging1 *pag;
286         int len1, len2, mi_type, tag;
287         char mi_string[GSM48_MI_SIZE];
288
289         /* is there enough room for the header + LV? */
290         if (msgb_l3len(msg) < sizeof(*pag) + 2) {
291                 LOGP(DRR, LOGL_ERROR, "PagingRequest is too short.\n");
292                 return -1;
293         }
294
295         pag = msgb_l3(msg);
296         len1 = pag->data[0];
297         mi_type = pag->data[1] & GSM_MI_TYPE_MASK;
298
299         if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1) {
300                 LOGP(DRR, LOGL_ERROR, "PagingRequest with wrong MI\n");
301                 return -1;
302         }
303
304         if (mi_type != GSM_MI_TYPE_NONE) {
305                 gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[1], len1);
306                 LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to %s M(%s) \n",
307                      pag_print_mode(pag->pag_mode),
308                      chan_need(pag->cneed1),
309                      mi_type_to_string(mi_type),
310                      mi_string);
311         }
312
313         /* check if we have a MI type in here */
314         if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3)
315                 return 0;
316
317         tag = pag->data[2 + len1 + 0];
318         len2 = pag->data[2 + len1 + 1];
319         mi_type = pag->data[2 + len1 + 2] & GSM_MI_TYPE_MASK;
320         if (tag == GSM48_IE_MOBILE_ID && mi_type != GSM_MI_TYPE_NONE) {
321                 if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3 + len2) {
322                         LOGP(DRR, LOGL_ERROR, "Optional MI does not fit here.\n");
323                         return -1;
324                 }
325
326                 gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2 + len1 + 2], len2);
327                 LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to %s M(%s) \n",
328                      pag_print_mode(pag->pag_mode),
329                      chan_need(pag->cneed2),
330                      mi_type_to_string(mi_type),
331                      mi_string);
332         }
333         return 0;
334 }
335
336 static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms)
337 {
338         struct gsm48_paging2 *pag;
339         int tag, len, mi_type;
340         char mi_string[GSM48_MI_SIZE];
341
342         if (msgb_l3len(msg) < sizeof(*pag)) {
343                 LOGP(DRR, LOGL_ERROR, "Paging2 message is too small.\n");
344                 return -1;
345         }
346
347         pag = msgb_l3(msg);
348         LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n",
349                      pag_print_mode(pag->pag_mode),
350                      chan_need(pag->cneed1), pag->tmsi1);
351         LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
352                      pag_print_mode(pag->pag_mode),
353                      chan_need(pag->cneed1), pag->tmsi2);
354
355         /* no optional element */
356         if (msgb_l3len(msg) < sizeof(*pag) + 3)
357                 return 0;
358
359         tag = pag->data[0];
360         len = pag->data[1];
361         mi_type = pag->data[2] & GSM_MI_TYPE_MASK;
362
363         if (tag != GSM48_IE_MOBILE_ID)
364                 return 0;
365
366         if (msgb_l3len(msg) < sizeof(*pag) + 3 + len) {
367                 LOGP(DRR, LOGL_ERROR, "Optional MI does not fit in here\n");
368                 return -1;
369         }
370
371         gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2], len);
372         LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to %s M(%s) \n",
373              pag_print_mode(pag->pag_mode),
374              "n/a ",
375              mi_type_to_string(mi_type),
376              mi_string);
377
378         return 0;
379 }
380
381 int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
382 {
383         struct gsm48_system_information_type_header *sih = msgb_l3(msg);
384         int rc = 0;
385
386         if (sih->rr_protocol_discriminator != GSM48_PDISC_RR)
387                 LOGP(DRR, LOGL_ERROR, "PCH pdisc != RR\n");
388
389         switch (sih->system_information) {
390         case GSM48_MT_RR_PAG_REQ_1:
391                 gsm48_rx_paging_p1(msg, ms);
392                 break;
393         case GSM48_MT_RR_PAG_REQ_2:
394                 gsm48_rx_paging_p2(msg, ms);
395                 break;
396         case GSM48_MT_RR_PAG_REQ_3:
397                 LOGP(DRR, LOGL_ERROR, "PAGING of type 3 is not implemented.\n");
398                 break;
399         case GSM48_MT_RR_IMM_ASS:
400                 gsm48_rx_imm_ass(msg, ms);
401                 break;
402         case GSM48_MT_RR_NOTIF_NCH:
403                 /* notification for voice call groups and such */
404                 break;
405         case 0x07:
406                 /* wireshark know that this is SI2 quater and for 3G interop */
407                 break;
408         default:
409                 LOGP(DRR, LOGL_NOTICE, "unknown PCH/AGCH type 0x%02x\n",
410                         sih->system_information);
411                 rc = -EINVAL;
412         }
413
414         return rc;
415 }
416
417 int gsm48_rx_bcch(struct msgb *msg, struct osmocom_ms *ms)
418 {
419         /* FIXME: we have lost the gsm frame time until here, need to store it
420          * in some msgb context */
421         //dump_bcch(dl->time.tc, ccch->data);
422         dump_bcch(ms, 0, msg->l3h);
423
424         /* Req channel logic */
425         if (app_state.ccch_enabled && (app_state.rach_count < 2)) {
426                 l1ctl_tx_rach_req(ms, app_state.rach_count, 0,
427                         app_state.ccch_mode == CCCH_MODE_COMBINED);
428                 app_state.rach_count++;
429         }
430
431         return 0;
432 }
433
434 void layer3_app_reset(void)
435 {
436         /* Reset state */
437         app_state.has_si1 = 0;
438         app_state.ccch_mode = CCCH_MODE_NONE;
439         app_state.ccch_enabled = 0;
440         app_state.rach_count = 0;
441
442         memset(&app_state.cell_arfcns, 0x00, sizeof(app_state.cell_arfcns));
443 }
444
445 static int signal_cb(unsigned int subsys, unsigned int signal,
446                      void *handler_data, void *signal_data)
447 {
448         struct osmocom_ms *ms;
449
450         if (subsys != SS_L1CTL)
451                 return 0;
452
453         switch (signal) {
454         case S_L1CTL_RESET:
455                 ms = signal_data;
456                 layer3_app_reset();
457                 return l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
458                                          L1CTL_FBSB_F_FB01SB, 100, 0,
459                                          CCCH_MODE_NONE);
460                 break;
461         }
462         return 0;
463 }
464
465
466 int l23_app_init(struct osmocom_ms *ms)
467 {
468         register_signal_handler(SS_L1CTL, &signal_cb, NULL);
469         l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
470         return layer3_init(ms);
471 }
472
473 static struct l23_app_info info = {
474         .copyright      = "Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>\n",
475         .contribution   = "Contributions by Holger Hans Peter Freyther\n",
476 };
477
478 struct l23_app_info *l23_app_info()
479 {
480         return &info;
481 }