237b990d3a6ea3bda1d08545e76039970b57c1a0
[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/protocol/gsm_04_08.h>
32
33 #include <osmocom/bb/common/logging.h>
34 #include <osmocom/bb/common/lapdm.h>
35 #include <osmocom/bb/misc/rslms.h>
36 #include <osmocom/bb/misc/layer3.h>
37 #include <osmocom/bb/common/osmocom_data.h>
38 #include <osmocom/bb/common/l1ctl.h>
39
40 static struct {
41         int has_si1;
42         int ccch_mode;
43         int ccch_enabled;
44         int rach_count;
45         struct gsm_sysinfo_freq cell_arfcns[1024];
46 } app_state;
47
48
49 static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
50 {
51         struct gsm48_system_information_type_header *si_hdr;
52         si_hdr = (struct gsm48_system_information_type_header *) data;
53
54         /* GSM 05.02 ยง6.3.1.3 Mapping of BCCH data */
55         switch (si_hdr->system_information) {
56         case GSM48_MT_RR_SYSINFO_1:
57                 fprintf(stderr, "\tSI1");
58 #ifdef BCCH_TC_CHECK
59                 if (tc != 0)
60                         fprintf(stderr, " on wrong TC");
61 #endif
62                 if (!app_state.has_si1) {
63                         struct gsm48_system_information_type_1 *si1 =
64                                 (struct gsm48_system_information_type_1 *)data;
65
66                         gsm48_decode_freq_list(&app_state.cell_arfcns,
67                                                si1->cell_channel_description,
68                                                sizeof(si1->cell_channel_description),
69                                                0xff, 0x01);
70
71                         app_state.has_si1 = 1;
72                 }
73                 break;
74         case GSM48_MT_RR_SYSINFO_2:
75                 fprintf(stderr, "\tSI2");
76 #ifdef BCCH_TC_CHECK
77                 if (tc != 1)
78                         fprintf(stderr, " on wrong TC");
79 #endif
80                 break;
81         case GSM48_MT_RR_SYSINFO_3:
82                 fprintf(stderr, "\tSI3");
83 #ifdef BCCH_TC_CHECK
84                 if (tc != 2 && tc != 6)
85                         fprintf(stderr, " on wrong TC");
86 #endif
87                 if (app_state.ccch_mode == CCCH_MODE_NONE) {
88                         struct gsm48_system_information_type_3 *si3 =
89                                 (struct gsm48_system_information_type_3 *)data;
90
91                         if (si3->control_channel_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
92                                 app_state.ccch_mode = CCCH_MODE_COMBINED;
93                         else
94                                 app_state.ccch_mode = CCCH_MODE_NON_COMBINED;
95
96                         l1ctl_tx_ccch_mode_req(ms, app_state.ccch_mode);
97                 }
98                 break;
99         case GSM48_MT_RR_SYSINFO_4:
100                 fprintf(stderr, "\tSI4");
101 #ifdef BCCH_TC_CHECK
102                 if (tc != 3 && tc != 7)
103                         fprintf(stderr, " on wrong TC");
104 #endif
105                 break;
106         case GSM48_MT_RR_SYSINFO_5:
107                 fprintf(stderr, "\tSI5");
108                 break;
109         case GSM48_MT_RR_SYSINFO_6:
110                 fprintf(stderr, "\tSI6");
111                 break;
112         case GSM48_MT_RR_SYSINFO_7:
113                 fprintf(stderr, "\tSI7");
114 #ifdef BCCH_TC_CHECK
115                 if (tc != 7)
116                         fprintf(stderr, " on wrong TC");
117 #endif
118                 break;
119         case GSM48_MT_RR_SYSINFO_8:
120                 fprintf(stderr, "\tSI8");
121 #ifdef BCCH_TC_CHECK
122                 if (tc != 3)
123                         fprintf(stderr, " on wrong TC");
124 #endif
125                 break;
126         case GSM48_MT_RR_SYSINFO_9:
127                 fprintf(stderr, "\tSI9");
128 #ifdef BCCH_TC_CHECK
129                 if (tc != 4)
130                         fprintf(stderr, " on wrong TC");
131 #endif
132                 break;
133         case GSM48_MT_RR_SYSINFO_13:
134                 fprintf(stderr, "\tSI13");
135 #ifdef BCCH_TC_CHECK
136                 if (tc != 4 && tc != 0)
137                         fprintf(stderr, " on wrong TC");
138 #endif
139                 break;
140         case GSM48_MT_RR_SYSINFO_16:
141                 fprintf(stderr, "\tSI16");
142 #ifdef BCCH_TC_CHECK
143                 if (tc != 6)
144                         fprintf(stderr, " on wrong TC");
145 #endif
146                 break;
147         case GSM48_MT_RR_SYSINFO_17:
148                 fprintf(stderr, "\tSI17");
149 #ifdef BCCH_TC_CHECK
150                 if (tc != 2)
151                         fprintf(stderr, " on wrong TC");
152 #endif
153                 break;
154         case GSM48_MT_RR_SYSINFO_2bis:
155                 fprintf(stderr, "\tSI2bis");
156 #ifdef BCCH_TC_CHECK
157                 if (tc != 5)
158                         fprintf(stderr, " on wrong TC");
159 #endif
160                 break;
161         case GSM48_MT_RR_SYSINFO_2ter:
162                 fprintf(stderr, "\tSI2ter");
163 #ifdef BCCH_TC_CHECK
164                 if (tc != 5 && tc != 4)
165                         fprintf(stderr, " on wrong TC");
166 #endif
167                 break;
168         case GSM48_MT_RR_SYSINFO_5bis:
169                 fprintf(stderr, "\tSI5bis");
170                 break;
171         case GSM48_MT_RR_SYSINFO_5ter:
172                 fprintf(stderr, "\tSI5ter");
173                 break;
174         default:
175                 fprintf(stderr, "\tUnknown SI");
176                 break;
177         };
178
179         fprintf(stderr, "\n");
180 }
181
182
183 /* send location updating request * (as part of RSLms EST IND /
184    LAPDm SABME) */
185 static int gsm48_tx_loc_upd_req(struct osmocom_ms *ms, uint8_t chan_nr)
186 {
187         struct msgb *msg = msgb_alloc_headroom(256, 16, "loc_upd_req");
188         struct gsm48_hdr *gh;
189         struct gsm48_loc_upd_req *lu_r;
190
191         DEBUGP(DMM, "chan_nr=%u\n", chan_nr);
192
193         msg->l3h = msgb_put(msg, sizeof(*gh));
194         gh = (struct gsm48_hdr *) msg->l3h;
195         gh->proto_discr = GSM48_PDISC_MM;
196         gh->msg_type = GSM48_MT_MM_LOC_UPD_REQUEST;
197         lu_r = (struct gsm48_loc_upd_req *) msgb_put(msg, sizeof(*lu_r));
198         lu_r->type = GSM48_LUPD_IMSI_ATT;
199         lu_r->key_seq = 0;
200         /* FIXME: set LAI and CM1 */
201         /* FIXME: set MI */
202         lu_r->mi_len = 0;
203
204         return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, chan_nr, 0, msg);
205 }
206
207 static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
208 {
209         struct gsm48_imm_ass *ia = msgb_l3(msg);
210         uint8_t ch_type, ch_subch, ch_ts;
211         int rv;
212
213         /* Discard packet TBF assignement */
214         if (ia->page_mode & 0xf0)
215                 return 0;
216
217         /* FIXME: compare RA and GSM time with when we sent RACH req */
218
219         rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);
220
221         if (!ia->chan_desc.h0.h) {
222                 /* Non-hopping */
223                 uint16_t arfcn;
224
225                 arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
226
227                 DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
228                         "ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
229                         ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
230                         ia->chan_desc.h0.tsc);
231
232                 /* request L1 to go to dedicated mode on assigned channel */
233                 rv = l1ctl_tx_dm_est_req_h0(ms,
234                         arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc,
235                         GSM48_CMODE_SIGN);
236         } else {
237                 /* Hopping */
238                 uint8_t maio, hsn, ma_len;
239                 uint16_t ma[64], arfcn;
240                 int i, j, k;
241
242                 hsn = ia->chan_desc.h1.hsn;
243                 maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
244
245                 DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
246                         "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
247                         ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
248                         ia->chan_desc.h1.tsc);
249
250                 /* decode mobile allocation */
251                 ma_len = 0;
252                 for (i=1, j=0; i<=1024; i++) {
253                         arfcn = i & 1023;
254                         if (app_state.cell_arfcns[arfcn].mask & 0x01) {
255                                 k = ia->mob_alloc_len - (j>>3) - 1;
256                                 if (ia->mob_alloc[k] & (1 << (j&7))) {
257                                         ma[ma_len++] = arfcn;
258                                 }
259                                 j++;
260                         }
261                 }
262
263                 /* request L1 to go to dedicated mode on assigned channel */
264                 rv = l1ctl_tx_dm_est_req_h1(ms,
265                         maio, hsn, ma, ma_len,
266                         ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc,
267                         GSM48_CMODE_SIGN);
268         }
269
270         DEBUGPC(DRR, "\n");
271
272         rv = gsm48_tx_loc_upd_req(ms, ia->chan_desc.chan_nr);
273
274         return rv;
275 }
276
277 int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
278 {
279         struct gsm48_system_information_type_header *sih = msgb_l3(msg);
280         int rc = 0;
281
282         if (sih->rr_protocol_discriminator != GSM48_PDISC_RR)
283                 LOGP(DRR, LOGL_ERROR, "PCH pdisc != RR\n");
284
285         switch (sih->system_information) {
286         case GSM48_MT_RR_PAG_REQ_1:
287         case GSM48_MT_RR_PAG_REQ_2:
288         case GSM48_MT_RR_PAG_REQ_3:
289                 /* FIXME: implement decoding of paging request */
290                 break;
291         case GSM48_MT_RR_IMM_ASS:
292                 rc = gsm48_rx_imm_ass(msg, ms);
293                 break;
294         default:
295                 LOGP(DRR, LOGL_NOTICE, "unknown PCH/AGCH type 0x%02x\n",
296                         sih->system_information);
297                 rc = -EINVAL;
298         }
299
300         return rc;
301 }
302
303 int gsm48_rx_bcch(struct msgb *msg, struct osmocom_ms *ms)
304 {
305         /* FIXME: we have lost the gsm frame time until here, need to store it
306          * in some msgb context */
307         //dump_bcch(dl->time.tc, ccch->data);
308         dump_bcch(ms, 0, msg->l3h);
309
310         /* Req channel logic */
311         if (app_state.ccch_enabled && (app_state.rach_count < 2)) {
312                 l1ctl_tx_rach_req(ms, app_state.rach_count, 0,
313                         app_state.ccch_mode == CCCH_MODE_COMBINED);
314                 app_state.rach_count++;
315         }
316
317         return 0;
318 }
319
320 void layer3_app_reset(void)
321 {
322         /* Reset state */
323         app_state.has_si1 = 0;
324         app_state.ccch_mode = CCCH_MODE_NONE;
325         app_state.ccch_enabled = 0;
326         app_state.rach_count = 0;
327
328         memset(&app_state.cell_arfcns, 0x00, sizeof(app_state.cell_arfcns));
329 }