further decouple lapdm code from osmocom_ms and l1ctl
[osmocom-bb.git] / src / host / layer23 / src / misc / app_cbch_sniff.c
1 /* CBCH passive sniffer */
2
3 /* (C) 2010 by Holger Hans Peter Freyther
4  * (C) 2010 by Harald Welte <laforge@gnumonks.org>
5  * (C) 2010 by Alex Badea <vamposdecampos@gmail.com>
6  *
7  * All Rights Reserved
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  */
24
25 #include <osmocom/bb/common/osmocom_data.h>
26 #include <osmocom/bb/common/l1ctl.h>
27 #include <osmocom/bb/common/lapdm.h>
28 #include <osmocom/bb/common/logging.h>
29 #include <osmocom/bb/common/l23_app.h>
30 #include <osmocom/bb/misc/layer3.h>
31
32 #include <osmocom/core/msgb.h>
33 #include <osmocom/core/talloc.h>
34 #include <osmocom/core/select.h>
35 #include <osmocom/core/signal.h>
36 #include <osmocom/gsm/rsl.h>
37
38 #include <l1ctl_proto.h>
39
40 struct osmocom_ms *g_ms;
41 struct gsm48_sysinfo g_sysinfo = {};
42
43 static int try_cbch(struct osmocom_ms *ms, struct gsm48_sysinfo *s)
44 {
45         if (!s->si1 || !s->si4)
46                 return 0;
47         if (!s->chan_nr) {
48                 LOGP(DRR, LOGL_INFO, "no CBCH chan_nr found\n");
49                 return 0;
50         }
51
52         if (s->h) {
53                 LOGP(DRR, LOGL_INFO, "chan_nr = 0x%02x TSC = %d  MAIO = %d  "
54                         "HSN = %d  hseq (%d): %s\n",
55                         s->chan_nr, s->tsc, s->maio, s->hsn,
56                         s->hopp_len,
57                         osmo_hexdump((unsigned char *) s->hopping, s->hopp_len * 2));
58                 return l1ctl_tx_dm_est_req_h1(ms,
59                         s->maio, s->hsn, s->hopping, s->hopp_len,
60                         s->chan_nr, s->tsc,
61                         GSM48_CMODE_SIGN);
62         } else {
63                 LOGP(DRR, LOGL_INFO, "chan_nr = 0x%02x TSC = %d  ARFCN = %d\n",
64                         s->chan_nr, s->tsc, s->arfcn);
65                 return l1ctl_tx_dm_est_req_h0(ms, s->arfcn,
66                         s->chan_nr, s->tsc, GSM48_CMODE_SIGN);
67         }
68 }
69
70
71 /* receive BCCH at RR layer */
72 static int bcch(struct osmocom_ms *ms, struct msgb *msg)
73 {
74         struct gsm48_system_information_type_header *sih = msgb_l3(msg);
75         struct gsm48_sysinfo *s = &g_sysinfo;
76
77         if (msgb_l3len(msg) != 23) {
78                 LOGP(DRR, LOGL_NOTICE, "Invalid BCCH message length\n");
79                 return -EINVAL;
80         }
81         switch (sih->system_information) {
82         case GSM48_MT_RR_SYSINFO_1:
83                 LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n");
84                 gsm48_decode_sysinfo1(s,
85                         (struct gsm48_system_information_type_1 *) sih,
86                         msgb_l3len(msg));
87                 return try_cbch(ms, s);
88         case GSM48_MT_RR_SYSINFO_4:
89                 LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4\n");
90                 gsm48_decode_sysinfo4(s,
91                         (struct gsm48_system_information_type_4 *) sih,
92                         msgb_l3len(msg));
93                 return try_cbch(ms, s);
94         default:
95                 return 0;
96         }
97 }
98
99 static int unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
100 {
101         struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
102         struct tlv_parsed tv;
103         uint8_t ch_type, ch_subch, ch_ts;
104
105         DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n",
106                 rllh->chan_nr, rllh->link_id);
107
108         rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh));
109         if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) {
110                 DEBUGP(DRSL, "UNIT_DATA_IND without L3 INFO ?!?\n");
111                 return -EIO;
112         }
113         msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO);
114
115         rsl_dec_chan_nr(rllh->chan_nr, &ch_type, &ch_subch, &ch_ts);
116         switch (ch_type) {
117         case RSL_CHAN_BCCH:
118                 return bcch(ms, msg);
119         default:
120                 return 0;
121         }
122 }
123
124 static int rcv_rll(struct osmocom_ms *ms, struct msgb *msg)
125 {
126         struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
127         int msg_type = rllh->c.msg_type;
128
129         if (msg_type == RSL_MT_UNIT_DATA_IND) {
130                 unit_data_ind(ms, msg);
131         } else
132                 LOGP(DRSL, LOGL_NOTICE, "RSLms message unhandled\n");
133
134         msgb_free(msg);
135
136         return 0;
137 }
138
139 static int rcv_rsl(struct msgb *msg, struct lapdm_entity *le, void *l3ctx)
140 {
141         struct osmocom_ms *ms = l3ctx;
142         struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
143         int rc = 0;
144
145         switch (rslh->msg_discr & 0xfe) {
146         case ABIS_RSL_MDISC_RLL:
147                 rc = rcv_rll(ms, msg);
148                 break;
149         default:
150                 LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
151                         rslh->msg_discr);
152                 msgb_free(msg);
153                 rc = -EINVAL;
154                 break;
155         }
156
157         return rc;
158 }
159
160 static int signal_cb(unsigned int subsys, unsigned int signal,
161                      void *handler_data, void *signal_data)
162 {
163         struct osmocom_ms *ms;
164
165         if (subsys != SS_L1CTL)
166                 return 0;
167
168         switch (signal) {
169         case S_L1CTL_RESET:
170         case S_L1CTL_FBSB_ERR:
171                 ms = g_ms;
172                 return l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
173                         L1CTL_FBSB_F_FB01SB, 100, 0, CCCH_MODE_COMBINED);
174         case S_L1CTL_FBSB_RESP:
175                 return 0;
176         }
177         return 0;
178 }
179
180 int l23_app_init(struct osmocom_ms *ms)
181 {
182         /* don't do layer3_init() as we don't want an actualy L3 */
183
184         g_ms = ms;
185         lapdm_channel_set_l1(&ms->lapdm_channel, &rcv_rsl, ms);
186
187         l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
188         /* FIXME: L1CTL_RES_T_FULL doesn't reset dedicated mode
189          * (if previously set), so we release it here. */
190         l1ctl_tx_dm_rel_req(ms);
191         return osmo_signal_register_handler(SS_L1CTL, &signal_cb, NULL);
192 }
193
194 static struct l23_app_info info = {
195         .copyright      = "Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>\n",
196         .contribution   = "Contributions by Holger Hans Peter Freyther\n",
197 };
198
199 struct l23_app_info *l23_app_info()
200 {
201         return &info;
202 }