[layer23] VTY command for changing LAI on SIM card
[osmocom-bb.git] / src / host / layer23 / src / common / l1ctl.c
1 /* Layer1 control code, talking L1CTL protocol with L1 on the phone */
2
3 /* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4  * (C) 2010 by Harald Welte <laforge@gnumonks.org>
5  *
6  * All Rights Reserved
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  */
23
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include <arpa/inet.h>
30
31 #include <l1ctl_proto.h>
32
33 #include <osmocore/signal.h>
34 #include <osmocore/logging.h>
35 #include <osmocore/timer.h>
36 #include <osmocore/msgb.h>
37 #include <osmocore/tlv.h>
38 #include <osmocore/gsm_utils.h>
39 #include <osmocore/gsmtap_util.h>
40 #include <osmocore/protocol/gsm_04_08.h>
41 #include <osmocore/protocol/gsm_08_58.h>
42 #include <osmocore/rsl.h>
43
44 #include <osmocom/bb/common/l1ctl.h>
45 #include <osmocom/bb/common/osmocom_data.h>
46 #include <osmocom/bb/common/l1l2_interface.h>
47 #include <osmocom/bb/common/lapdm.h>
48 #include <osmocom/bb/common/logging.h>
49
50 static struct msgb *osmo_l1_alloc(uint8_t msg_type)
51 {
52         struct l1ctl_hdr *l1h;
53         struct msgb *msg = msgb_alloc_headroom(256, 4, "osmo_l1");
54
55         if (!msg) {
56                 LOGP(DL1C, LOGL_ERROR, "Failed to allocate memory.\n");
57                 return NULL;
58         }
59
60         msg->l1h = msgb_put(msg, sizeof(*l1h));
61         l1h = (struct l1ctl_hdr *) msg->l1h;
62         l1h->msg_type = msg_type;
63         
64         return msg;
65 }
66
67
68 static int osmo_make_band_arfcn(struct osmocom_ms *ms, uint16_t arfcn)
69 {
70         /* TODO: Include the band */
71         return arfcn;
72 }
73
74 static int rx_l1_fbsb_conf(struct osmocom_ms *ms, struct msgb *msg)
75 {
76         struct l1ctl_info_dl *dl;
77         struct l1ctl_fbsb_conf *sb;
78         struct gsm_time tm;
79         struct osmobb_fbsb_res fr;
80
81         if (msgb_l3len(msg) < sizeof(*dl) + sizeof(*sb)) {
82                 LOGP(DL1C, LOGL_ERROR, "FBSB RESP: MSG too short %u\n",
83                         msgb_l3len(msg));
84                 return -1;
85         }
86
87         dl = (struct l1ctl_info_dl *) msg->l1h;
88         sb = (struct l1ctl_fbsb_conf *) dl->payload;
89
90         printf("snr=%04x, arfcn=%u result=%u\n", dl->snr, ntohs(dl->band_arfcn),
91                 sb->result);
92
93         if (sb->result != 0) {
94                 LOGP(DL1C, LOGL_ERROR, "FBSB RESP: result=%u\n", sb->result);
95                 dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_ERR, ms);
96                 return 0;
97         }
98
99         gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
100         DEBUGP(DL1C, "SCH: SNR: %u TDMA: (%.4u/%.2u/%.2u) bsic: %d\n",
101                 dl->snr, tm.t1, tm.t2, tm.t3, sb->bsic);
102         fr.ms = ms;
103         fr.snr = dl->snr;
104         fr.bsic = sb->bsic;
105         dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_RESP, &fr);
106
107         return 0;
108 }
109
110 static int rx_l1_rach_conf(struct osmocom_ms *ms, struct msgb *msg)
111 {
112         struct l1ctl_info_dl *dl;
113
114         if (msgb_l2len(msg) < sizeof(*dl)) {
115                 LOGP(DL1C, LOGL_ERROR, "RACH CONF: MSG too short %u\n",
116                         msgb_l3len(msg));
117                 msgb_free(msg);
118                 return -1;
119         }
120
121         dl = (struct l1ctl_info_dl *) msg->l1h;
122
123         l2_ph_chan_conf(msg, ms, dl);
124
125         return 0;
126 }
127
128 /* Receive L1CTL_DATA_IND (Data Indication from L1) */
129 static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg)
130 {
131         struct l1ctl_info_dl *dl, dl_cpy;
132         struct l1ctl_data_ind *ccch;
133         struct lapdm_entity *le;
134         struct rx_meas_stat *meas = &ms->meas;
135         uint8_t chan_type, chan_ts, chan_ss;
136         uint8_t gsmtap_chan_type;
137         struct gsm_time tm;
138
139         if (msgb_l3len(msg) < sizeof(*ccch)) {
140                 LOGP(DL1C, LOGL_ERROR, "MSG too short Data Ind: %u\n",
141                         msgb_l3len(msg));
142                 msgb_free(msg);
143                 return -1;
144         }
145
146         dl = (struct l1ctl_info_dl *) msg->l1h;
147         msg->l2h = dl->payload;
148         ccch = (struct l1ctl_data_ind *) msg->l2h;
149
150         gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
151         rsl_dec_chan_nr(dl->chan_nr, &chan_type, &chan_ss, &chan_ts);
152         DEBUGP(DL1C, "%s (%.4u/%.2u/%.2u) %d dBm: %s\n",
153                 rsl_chan_nr_str(dl->chan_nr), tm.t1, tm.t2, tm.t3,
154                 (int)dl->rx_level-110,
155                 hexdump(ccch->data, sizeof(ccch->data)));
156
157         meas->last_fn = ntohl(dl->frame_nr);
158         meas->frames++;
159         meas->snr += dl->snr;
160         meas->berr += dl->num_biterr;
161         meas->rxlev += dl->rx_level;
162
163         if (dl->num_biterr) {
164 printf("Dropping frame with %u bit errors\n", dl->num_biterr);
165                 LOGP(DL1C, LOGL_NOTICE, "Dropping frame with %u bit errors\n",
166                         dl->num_biterr);
167                 return 0;
168         }
169
170         /* send CCCH data via GSMTAP */
171         gsmtap_chan_type = chantype_rsl2gsmtap(chan_type, dl->link_id);
172         gsmtap_sendmsg(ntohs(dl->band_arfcn), chan_ts, gsmtap_chan_type, chan_ss,
173                         tm.fn, dl->rx_level-110, dl->snr, ccch->data,
174                         sizeof(ccch->data));
175
176         /* determine LAPDm entity based on SACCH or not */
177         if (dl->link_id & 0x40)
178                 le = &ms->l2_entity.lapdm_acch;
179         else
180                 le = &ms->l2_entity.lapdm_dcch;
181         /* make local stack copy of l1ctl_info_dl, as LAPDm will
182          * overwrite skb hdr */
183         memcpy(&dl_cpy, dl, sizeof(dl_cpy));
184
185         /* pull the L1 header from the msgb */
186         msgb_pull(msg, msg->l2h - (msg->l1h-sizeof(struct l1ctl_hdr)));
187         msg->l1h = NULL;
188
189         /* send it up into LAPDm */
190         l2_ph_data_ind(msg, le, &dl_cpy);
191
192         return 0;
193 }
194
195 /* Receive L1CTL_DATA_CONF (Data Confirm from L1) */
196 static int rx_ph_data_conf(struct osmocom_ms *ms, struct msgb *msg)
197 {
198         struct l1ctl_info_dl *dl;
199         struct lapdm_entity *le;
200
201         dl = (struct l1ctl_info_dl *) msg->l1h;
202
203         /* determine LAPDm entity based on SACCH or not */
204         if (dl->link_id & 0x40)
205                 le = &ms->l2_entity.lapdm_acch;
206         else
207                 le = &ms->l2_entity.lapdm_dcch;
208
209         /* send it up into LAPDm */
210         l2_ph_data_conf(msg, le);
211
212         return 0;
213 }
214
215 /* Transmit L1CTL_DATA_REQ */
216 int l1ctl_tx_data_req(struct osmocom_ms *ms, struct msgb *msg,
217                       uint8_t chan_nr, uint8_t link_id)
218 {
219         struct l1ctl_hdr *l1h;
220         struct l1ctl_info_ul *l1i_ul;
221         uint8_t chan_type, chan_ts, chan_ss;
222         uint8_t gsmtap_chan_type;
223
224         DEBUGP(DL1C, "(%s)\n", hexdump(msg->l2h, msgb_l2len(msg)));
225
226         if (msgb_l2len(msg) > 23) {
227                 LOGP(DL1C, LOGL_ERROR, "L1 cannot handle message length "
228                         "> 23 (%u)\n", msgb_l2len(msg));
229                 msgb_free(msg);
230                 return -EINVAL;
231         } else if (msgb_l2len(msg) < 23)
232                 LOGP(DL1C, LOGL_ERROR, "L1 message length < 23 (%u) "
233                         "doesn't seem right!\n", msgb_l2len(msg));
234
235         /* send copy via GSMTAP */
236         rsl_dec_chan_nr(chan_nr, &chan_type, &chan_ss, &chan_ts);
237         gsmtap_chan_type = chantype_rsl2gsmtap(chan_type, link_id);
238         gsmtap_sendmsg(0|0x4000, chan_ts, gsmtap_chan_type, chan_ss,
239                         0, 127, 255, msg->l2h, msgb_l2len(msg));
240
241         /* prepend uplink info header */
242         l1i_ul = (struct l1ctl_info_ul *) msgb_push(msg, sizeof(*l1i_ul));
243
244         l1i_ul->chan_nr = chan_nr;
245         l1i_ul->link_id = link_id;
246
247         /* prepend l1 header */
248         msg->l1h = msgb_push(msg, sizeof(*l1h));
249         l1h = (struct l1ctl_hdr *) msg->l1h;
250         l1h->msg_type = L1CTL_DATA_REQ;
251
252         return osmo_send_l1(ms, msg);
253 }
254
255 /* Transmit FBSB_REQ */
256 int l1ctl_tx_fbsb_req(struct osmocom_ms *ms, uint16_t arfcn,
257                       uint8_t flags, uint16_t timeout, uint8_t sync_info_idx,
258                       uint8_t ccch_mode)
259 {
260         struct msgb *msg;
261         struct l1ctl_fbsb_req *req;
262
263         printf("Sync Req\n");
264
265         msg = osmo_l1_alloc(L1CTL_FBSB_REQ);
266         if (!msg)
267                 return -1;
268
269         memset(&ms->meas, 0, sizeof(ms->meas));
270
271         req = (struct l1ctl_fbsb_req *) msgb_put(msg, sizeof(*req));
272         req->band_arfcn = htons(osmo_make_band_arfcn(ms, arfcn));
273         req->timeout = htons(timeout);
274         /* Threshold when to consider FB_MODE1: 4kHz - 1kHz */
275         req->freq_err_thresh1 = htons(4000 - 1000);
276         /* Threshold when to consider SCH: 1kHz - 200Hz */
277         req->freq_err_thresh2 = htons(1000 - 200);
278         /* not used yet! */
279         req->num_freqerr_avg = 3;
280         req->flags = flags;
281         req->sync_info_idx = sync_info_idx;
282         req->ccch_mode = ccch_mode;
283
284         return osmo_send_l1(ms, msg);
285 }
286
287 /* Transmit L1CTL_CCCH_MODE_REQ */
288 int l1ctl_tx_ccch_mode_req(struct osmocom_ms *ms, uint8_t ccch_mode)
289 {
290         struct msgb *msg;
291         struct l1ctl_ccch_mode_req *req;
292
293         printf("CCCH Mode Req\n");
294
295         msg = osmo_l1_alloc(L1CTL_CCCH_MODE_REQ);
296         if (!msg)
297                 return -1;
298
299         req = (struct l1ctl_ccch_mode_req *) msgb_put(msg, sizeof(*req));
300         req->ccch_mode = ccch_mode;
301
302         return osmo_send_l1(ms, msg);
303 }
304
305 /* Transmit L1CTL_TCH_MODE_REQ */
306 int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode)
307 {
308         struct msgb *msg;
309         struct l1ctl_tch_mode_req *req;
310
311         printf("TCH Mode Req\n");
312
313         msg = osmo_l1_alloc(L1CTL_TCH_MODE_REQ);
314         if (!msg)
315                 return -1;
316
317         req = (struct l1ctl_tch_mode_req *) msgb_put(msg, sizeof(*req));
318         req->tch_mode = tch_mode;
319
320         return osmo_send_l1(ms, msg);
321 }
322
323 /* Transmit L1CTL_PARAM_REQ */
324 int l1ctl_tx_param_req(struct osmocom_ms *ms, uint8_t ta, uint8_t tx_power)
325 {
326         struct msgb *msg;
327         struct l1ctl_info_ul *ul;
328         struct l1ctl_par_req *req;
329
330         msg = osmo_l1_alloc(L1CTL_PARAM_REQ);
331         if (!msg)
332                 return -1;
333
334         DEBUGP(DL1C, "PARAM Req. ta=%d, tx_power=%d\n", ta, tx_power);
335         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
336         req = (struct l1ctl_par_req *) msgb_put(msg, sizeof(*req));
337         req->tx_power = tx_power;
338         req->ta = ta;
339
340         return osmo_send_l1(ms, msg);
341 }
342
343 /* Transmit L1CTL_CRYPTO_REQ */
344 int l1ctl_tx_crypto_req(struct osmocom_ms *ms, uint8_t algo, uint8_t *key,
345         uint8_t len)
346 {
347         struct msgb *msg;
348         struct l1ctl_info_ul *ul;
349         struct l1ctl_crypto_req *req;
350
351         msg = osmo_l1_alloc(L1CTL_CRYPTO_REQ);
352         if (!msg)
353                 return -1;
354
355         DEBUGP(DL1C, "CRYPTO Req. algo=%d, len=%d\n", algo, len);
356         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
357         req = (struct l1ctl_crypto_req *) msgb_put(msg, sizeof(*req) + len);
358         req->algo = algo;
359         if (len)
360                 memcpy(req->key, key, len);
361
362         return osmo_send_l1(ms, msg);
363 }
364
365 /* Transmit L1CTL_RACH_REQ */
366 int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint8_t fn51,
367         uint8_t mf_off)
368 {
369         struct msgb *msg;
370         struct l1ctl_info_ul *ul;
371         struct l1ctl_rach_req *req;
372
373         msg = osmo_l1_alloc(L1CTL_RACH_REQ);
374         if (!msg)
375                 return -1;
376
377         DEBUGP(DL1C, "RACH Req. fn51=%d, mf_off=%d\n", fn51, mf_off);
378         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
379         req = (struct l1ctl_rach_req *) msgb_put(msg, sizeof(*req));
380         req->ra = ra;
381         req->fn51 = fn51;
382         req->mf_off = mf_off;
383
384         return osmo_send_l1(ms, msg);
385 }
386
387 /* Transmit L1CTL_DM_EST_REQ */
388 int l1ctl_tx_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
389                            uint8_t chan_nr, uint8_t tsc)
390 {
391         struct msgb *msg;
392         struct l1ctl_info_ul *ul;
393         struct l1ctl_dm_est_req *req;
394
395         msg = osmo_l1_alloc(L1CTL_DM_EST_REQ);
396         if (!msg)
397                 return -1;
398
399         printf("Tx Dedic.Mode Est Req (arfcn=%u, chan_nr=0x%02x)\n",
400                 band_arfcn, chan_nr);
401
402         memset(&ms->meas, 0, sizeof(ms->meas));
403
404         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
405         ul->chan_nr = chan_nr;
406         ul->link_id = 0;
407
408         req = (struct l1ctl_dm_est_req *) msgb_put(msg, sizeof(*req));
409         req->tsc = tsc;
410         req->h = 0;
411         req->h0.band_arfcn = htons(band_arfcn);
412
413         return osmo_send_l1(ms, msg);
414 }
415
416 int l1ctl_tx_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
417                            uint16_t *ma, uint8_t ma_len,
418                            uint8_t chan_nr, uint8_t tsc)
419 {
420         struct msgb *msg;
421         struct l1ctl_info_ul *ul;
422         struct l1ctl_dm_est_req *req;
423         int i;
424
425         msg = osmo_l1_alloc(L1CTL_DM_EST_REQ);
426         if (!msg)
427                 return -1;
428
429         printf("Tx Dedic.Mode Est Req (maio=%u, hsn=%u, "
430                 "chan_nr=0x%02x)\n", maio, hsn, chan_nr);
431
432         memset(&ms->meas, 0, sizeof(ms->meas));
433
434         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
435         ul->chan_nr = chan_nr;
436         ul->link_id = 0;
437
438         req = (struct l1ctl_dm_est_req *) msgb_put(msg, sizeof(*req));
439         req->tsc = tsc;
440         req->h = 1;
441         req->h1.maio = maio;
442         req->h1.hsn = hsn;
443         req->h1.n = ma_len;
444         for (i = 0; i < ma_len; i++)
445                 req->h1.ma[i] = htons(ma[i]);
446
447         return osmo_send_l1(ms, msg);
448 }
449
450 /* Transmit L1CTL_DM_FREQ_REQ */
451 int l1ctl_tx_dm_freq_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
452                             uint8_t tsc, uint16_t fn)
453 {
454         struct msgb *msg;
455         struct l1ctl_info_ul *ul;
456         struct l1ctl_dm_freq_req *req;
457
458         msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
459         if (!msg)
460                 return -1;
461
462         printf("Tx Dedic.Mode Freq Req (arfcn=%u, fn=%d)\n",
463                 band_arfcn, fn);
464
465         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
466         ul->chan_nr = 0;
467         ul->link_id = 0;
468
469         req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
470         req->fn = htons(fn);
471         req->tsc = tsc;
472         req->h = 0;
473         req->h0.band_arfcn = htons(band_arfcn);
474
475         return osmo_send_l1(ms, msg);
476 }
477
478 int l1ctl_tx_dm_freq_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
479                             uint16_t *ma, uint8_t ma_len,
480                             uint8_t tsc, uint16_t fn)
481 {
482         struct msgb *msg;
483         struct l1ctl_info_ul *ul;
484         struct l1ctl_dm_freq_req *req;
485         int i;
486
487         msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
488         if (!msg)
489                 return -1;
490
491         printf("Tx Dedic.Mode Freq Req (maio=%u, hsn=%u, "
492                 "fn=%d)\n", maio, hsn, fn);
493
494         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
495         ul->chan_nr = 0;
496         ul->link_id = 0;
497
498         req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
499         req->fn = htons(fn);
500         req->tsc = tsc;
501         req->h = 1;
502         req->h1.maio = maio;
503         req->h1.hsn = hsn;
504         req->h1.n = ma_len;
505         for (i = 0; i < ma_len; i++)
506                 req->h1.ma[i] = htons(ma[i]);
507
508         return osmo_send_l1(ms, msg);
509 }
510
511 /* Transmit L1CTL_DM_REL_REQ */
512 int l1ctl_tx_dm_rel_req(struct osmocom_ms *ms)
513 {
514         struct msgb *msg;
515         struct l1ctl_info_ul *ul;
516
517         msg = osmo_l1_alloc(L1CTL_DM_REL_REQ);
518         if (!msg)
519                 return -1;
520
521         printf("Tx Dedic.Mode Rel Req\n");
522
523         memset(&ms->meas, 0, sizeof(ms->meas));
524
525         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
526
527         return osmo_send_l1(ms, msg);
528 }
529
530 int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len)
531 {
532         struct msgb *msg;
533         uint8_t *data;
534         unsigned int i;
535
536         msg = osmo_l1_alloc(L1CTL_ECHO_REQ);
537         if (!msg)
538                 return -1;
539
540         data = msgb_put(msg, len);
541         for (i = 0; i < len; i++)
542                 data[i] = i % 8;
543
544         return osmo_send_l1(ms, msg);
545 }
546
547 int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length)
548 {
549         struct msgb *msg;
550         uint8_t *dat;
551
552         msg = osmo_l1_alloc(L1CTL_SIM_REQ);
553         if (!msg)
554                 return -1;
555
556         dat = msgb_put(msg, length);
557         memcpy(dat, data, length);
558
559         return osmo_send_l1(ms, msg);
560 }
561
562 /* just forward the SIM response to the SIM handler */
563 static int rx_l1_sim_conf(struct osmocom_ms *ms, struct msgb *msg)
564 {
565         uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
566         uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
567         
568         printf("SIM %s\n", hexdump(data, len));
569         
570         /* pull the L1 header from the msgb */
571         msgb_pull(msg, sizeof(struct l1ctl_hdr));
572         msg->l1h = NULL;
573
574         sim_apdu_resp(ms, msg);
575         
576         return 0;
577 }
578
579 /* Transmit L1CTL_PM_REQ */
580 int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
581                           uint16_t arfcn_to)
582 {
583         struct msgb *msg;
584         struct l1ctl_pm_req *pm;
585
586         msg = osmo_l1_alloc(L1CTL_PM_REQ);
587         if (!msg)
588                 return -1;
589
590         printf("Tx PM Req (%u-%u)\n", arfcn_from, arfcn_to);
591         pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
592         pm->type = 1;
593         pm->range.band_arfcn_from = htons(arfcn_from);
594         pm->range.band_arfcn_to = htons(arfcn_to);
595
596         return osmo_send_l1(ms, msg);
597 }
598
599 /* Transmit L1CTL_RESET_REQ */
600 int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type)
601 {
602         struct msgb *msg;
603         struct l1ctl_reset *res;
604
605         msg = osmo_l1_alloc(L1CTL_RESET_REQ);
606         if (!msg)
607                 return -1;
608
609         printf("Tx Reset Req (%u)\n", type);
610         res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
611         res->type = type;
612
613         return osmo_send_l1(ms, msg);
614 }
615
616 /* Receive L1CTL_RESET_IND */
617 static int rx_l1_reset(struct osmocom_ms *ms)
618 {
619         printf("Layer1 Reset indication\n");
620         dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms);
621
622         return 0;
623 }
624
625 /* Receive L1CTL_PM_CONF */
626 static int rx_l1_pm_conf(struct osmocom_ms *ms, struct msgb *msg)
627 {
628         struct l1ctl_pm_conf *pmr;
629
630         for (pmr = (struct l1ctl_pm_conf *) msg->l1h;
631              (uint8_t *) pmr < msg->tail; pmr++) {
632                 struct osmobb_meas_res mr;
633                 DEBUGP(DL1C, "PM MEAS: ARFCN: %4u RxLev: %3d %3d\n",
634                         ntohs(pmr->band_arfcn), pmr->pm[0], pmr->pm[1]);
635                 mr.band_arfcn = ntohs(pmr->band_arfcn);
636                 mr.rx_lev = pmr->pm[0];
637                 mr.ms = ms;
638                 dispatch_signal(SS_L1CTL, S_L1CTL_PM_RES, &mr);
639         }
640         return 0;
641 }
642
643 /* Receive L1CTL_CCCH_MODE_CONF */
644 static int rx_l1_ccch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
645 {
646         struct osmobb_ccch_mode_conf mc;
647         struct l1ctl_ccch_mode_conf *conf;
648
649         if (msgb_l3len(msg) < sizeof(*conf)) {
650                 LOGP(DL1C, LOGL_ERROR, "MODE CONF: MSG too short %u\n",
651                         msgb_l3len(msg));
652                 return -1;
653         }
654
655         conf = (struct l1ctl_ccch_mode_conf *) msg->l1h;
656
657         printf("mode=%u\n", conf->ccch_mode);
658
659         mc.ccch_mode = conf->ccch_mode;
660         mc.ms = ms;
661         dispatch_signal(SS_L1CTL, S_L1CTL_CCCH_MODE_CONF, &mc);
662
663         return 0;
664 }
665
666 /* Receive L1CTL_TCH_MODE_CONF */
667 static int rx_l1_tch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
668 {
669         struct osmobb_tch_mode_conf mc;
670         struct l1ctl_tch_mode_conf *conf;
671
672         if (msgb_l3len(msg) < sizeof(*conf)) {
673                 LOGP(DL1C, LOGL_ERROR, "MODE CONF: MSG too short %u\n",
674                         msgb_l3len(msg));
675                 return -1;
676         }
677
678         conf = (struct l1ctl_tch_mode_conf *) msg->l1h;
679
680         printf("mode=%u\n", conf->tch_mode);
681
682         mc.tch_mode = conf->tch_mode;
683         mc.ms = ms;
684         dispatch_signal(SS_L1CTL, S_L1CTL_TCH_MODE_CONF, &mc);
685
686         return 0;
687 }
688
689 /* Receive incoming data from L1 using L1CTL format */
690 int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
691 {
692         int rc = 0;
693         struct l1ctl_hdr *l1h;
694         struct l1ctl_info_dl *dl;
695
696         if (msgb_l2len(msg) < sizeof(*dl)) {
697                 LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n",
698                         msgb_l2len(msg));
699                 msgb_free(msg);
700                 return -1;
701         }
702
703         l1h = (struct l1ctl_hdr *) msg->l1h;
704
705         /* move the l1 header pointer to point _BEHIND_ l1ctl_hdr,
706            as the l1ctl header is of no interest to subsequent code */
707         msg->l1h = l1h->data;
708
709         switch (l1h->msg_type) {
710         case L1CTL_FBSB_CONF:
711                 rc = rx_l1_fbsb_conf(ms, msg);
712                 msgb_free(msg);
713                 break;
714         case L1CTL_DATA_IND:
715                 rc = rx_ph_data_ind(ms, msg);
716                 break;
717         case L1CTL_DATA_CONF:
718                 rc = rx_ph_data_conf(ms, msg);
719                 break;
720         case L1CTL_RESET_IND:
721         case L1CTL_RESET_CONF:
722                 rc = rx_l1_reset(ms);
723                 msgb_free(msg);
724                 break;
725         case L1CTL_PM_CONF:
726                 rc = rx_l1_pm_conf(ms, msg);
727                 msgb_free(msg);
728                 if (l1h->flags & L1CTL_F_DONE)
729                         dispatch_signal(SS_L1CTL, S_L1CTL_PM_DONE, ms);
730                 break;
731         case L1CTL_RACH_CONF:
732                 rc = rx_l1_rach_conf(ms, msg);
733                 break;
734         case L1CTL_CCCH_MODE_CONF:
735                 rc = rx_l1_ccch_mode_conf(ms, msg);
736                 msgb_free(msg);
737                 break;
738         case L1CTL_TCH_MODE_CONF:
739                 rc = rx_l1_tch_mode_conf(ms, msg);
740                 msgb_free(msg);
741                 break;
742         case L1CTL_SIM_CONF:
743                 rc = rx_l1_sim_conf(ms, msg);
744                 break;
745         default:
746                 fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type);
747                 msgb_free(msg);
748                 break;
749         }
750
751         return rc;
752 }