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