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