l1ctl: Add initial tch_mode value in DM_EST_REQ
[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         LOGP(DL1C, LOGL_INFO, "snr=%04x, arfcn=%u result=%u\n", dl->snr,
91                 ntohs(dl->band_arfcn), 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         LOGP(DL1C, LOGL_INFO, "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         LOGP(DL1C, LOGL_INFO, "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         LOGP(DL1C, LOGL_INFO, "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, uint8_t tch_mode)
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         LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Est Req (arfcn=%u, "
400                 "chan_nr=0x%02x)\n", 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         req->tch_mode = tch_mode;
413
414         return osmo_send_l1(ms, msg);
415 }
416
417 int l1ctl_tx_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
418                            uint16_t *ma, uint8_t ma_len,
419                            uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode)
420 {
421         struct msgb *msg;
422         struct l1ctl_info_ul *ul;
423         struct l1ctl_dm_est_req *req;
424         int i;
425
426         msg = osmo_l1_alloc(L1CTL_DM_EST_REQ);
427         if (!msg)
428                 return -1;
429
430         LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Est Req (maio=%u, hsn=%u, "
431                 "chan_nr=0x%02x)\n", maio, hsn, chan_nr);
432
433         memset(&ms->meas, 0, sizeof(ms->meas));
434
435         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
436         ul->chan_nr = chan_nr;
437         ul->link_id = 0;
438
439         req = (struct l1ctl_dm_est_req *) msgb_put(msg, sizeof(*req));
440         req->tsc = tsc;
441         req->h = 1;
442         req->h1.maio = maio;
443         req->h1.hsn = hsn;
444         req->h1.n = ma_len;
445         for (i = 0; i < ma_len; i++)
446                 req->h1.ma[i] = htons(ma[i]);
447         req->tch_mode = tch_mode;
448
449         return osmo_send_l1(ms, msg);
450 }
451
452 /* Transmit L1CTL_DM_FREQ_REQ */
453 int l1ctl_tx_dm_freq_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
454                             uint8_t tsc, uint16_t fn)
455 {
456         struct msgb *msg;
457         struct l1ctl_info_ul *ul;
458         struct l1ctl_dm_freq_req *req;
459
460         msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
461         if (!msg)
462                 return -1;
463
464         LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Freq Req (arfcn=%u, fn=%d)\n",
465                 band_arfcn, fn);
466
467         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
468         ul->chan_nr = 0;
469         ul->link_id = 0;
470
471         req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
472         req->fn = htons(fn);
473         req->tsc = tsc;
474         req->h = 0;
475         req->h0.band_arfcn = htons(band_arfcn);
476
477         return osmo_send_l1(ms, msg);
478 }
479
480 int l1ctl_tx_dm_freq_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
481                             uint16_t *ma, uint8_t ma_len,
482                             uint8_t tsc, uint16_t fn)
483 {
484         struct msgb *msg;
485         struct l1ctl_info_ul *ul;
486         struct l1ctl_dm_freq_req *req;
487         int i;
488
489         msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
490         if (!msg)
491                 return -1;
492
493         LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Freq Req (maio=%u, hsn=%u, "
494                 "fn=%d)\n", maio, hsn, fn);
495
496         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
497         ul->chan_nr = 0;
498         ul->link_id = 0;
499
500         req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
501         req->fn = htons(fn);
502         req->tsc = tsc;
503         req->h = 1;
504         req->h1.maio = maio;
505         req->h1.hsn = hsn;
506         req->h1.n = ma_len;
507         for (i = 0; i < ma_len; i++)
508                 req->h1.ma[i] = htons(ma[i]);
509
510         return osmo_send_l1(ms, msg);
511 }
512
513 /* Transmit L1CTL_DM_REL_REQ */
514 int l1ctl_tx_dm_rel_req(struct osmocom_ms *ms)
515 {
516         struct msgb *msg;
517         struct l1ctl_info_ul *ul;
518
519         msg = osmo_l1_alloc(L1CTL_DM_REL_REQ);
520         if (!msg)
521                 return -1;
522
523         LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Rel Req\n");
524
525         memset(&ms->meas, 0, sizeof(ms->meas));
526
527         ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
528
529         return osmo_send_l1(ms, msg);
530 }
531
532 int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len)
533 {
534         struct msgb *msg;
535         uint8_t *data;
536         unsigned int i;
537
538         msg = osmo_l1_alloc(L1CTL_ECHO_REQ);
539         if (!msg)
540                 return -1;
541
542         data = msgb_put(msg, len);
543         for (i = 0; i < len; i++)
544                 data[i] = i % 8;
545
546         return osmo_send_l1(ms, msg);
547 }
548
549 int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length)
550 {
551         struct msgb *msg;
552         uint8_t *dat;
553
554         msg = osmo_l1_alloc(L1CTL_SIM_REQ);
555         if (!msg)
556                 return -1;
557
558         dat = msgb_put(msg, length);
559         memcpy(dat, data, length);
560
561         return osmo_send_l1(ms, msg);
562 }
563
564 /* just forward the SIM response to the SIM handler */
565 static int rx_l1_sim_conf(struct osmocom_ms *ms, struct msgb *msg)
566 {
567         uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
568         uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
569         
570         LOGP(DL1C, LOGL_INFO, "SIM %s\n", hexdump(data, len));
571         
572         /* pull the L1 header from the msgb */
573         msgb_pull(msg, sizeof(struct l1ctl_hdr));
574         msg->l1h = NULL;
575
576         sim_apdu_resp(ms, msg);
577         
578         return 0;
579 }
580
581 /* Transmit L1CTL_PM_REQ */
582 int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
583                           uint16_t arfcn_to)
584 {
585         struct msgb *msg;
586         struct l1ctl_pm_req *pm;
587
588         msg = osmo_l1_alloc(L1CTL_PM_REQ);
589         if (!msg)
590                 return -1;
591
592         LOGP(DL1C, LOGL_INFO, "Tx PM Req (%u-%u)\n", arfcn_from, arfcn_to);
593         pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
594         pm->type = 1;
595         pm->range.band_arfcn_from = htons(arfcn_from);
596         pm->range.band_arfcn_to = htons(arfcn_to);
597
598         return osmo_send_l1(ms, msg);
599 }
600
601 /* Transmit L1CTL_RESET_REQ */
602 int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type)
603 {
604         struct msgb *msg;
605         struct l1ctl_reset *res;
606
607         msg = osmo_l1_alloc(L1CTL_RESET_REQ);
608         if (!msg)
609                 return -1;
610
611         LOGP(DL1C, LOGL_INFO, "Tx Reset Req (%u)\n", type);
612         res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
613         res->type = type;
614
615         return osmo_send_l1(ms, msg);
616 }
617
618 /* Receive L1CTL_RESET_IND */
619 static int rx_l1_reset(struct osmocom_ms *ms)
620 {
621         LOGP(DL1C, LOGL_INFO, "Layer1 Reset indication\n");
622         dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms);
623
624         return 0;
625 }
626
627 /* Receive L1CTL_PM_CONF */
628 static int rx_l1_pm_conf(struct osmocom_ms *ms, struct msgb *msg)
629 {
630         struct l1ctl_pm_conf *pmr;
631
632         for (pmr = (struct l1ctl_pm_conf *) msg->l1h;
633              (uint8_t *) pmr < msg->tail; pmr++) {
634                 struct osmobb_meas_res mr;
635                 DEBUGP(DL1C, "PM MEAS: ARFCN: %4u RxLev: %3d %3d\n",
636                         ntohs(pmr->band_arfcn), pmr->pm[0], pmr->pm[1]);
637                 mr.band_arfcn = ntohs(pmr->band_arfcn);
638                 mr.rx_lev = pmr->pm[0];
639                 mr.ms = ms;
640                 dispatch_signal(SS_L1CTL, S_L1CTL_PM_RES, &mr);
641         }
642         return 0;
643 }
644
645 /* Receive L1CTL_CCCH_MODE_CONF */
646 static int rx_l1_ccch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
647 {
648         struct osmobb_ccch_mode_conf mc;
649         struct l1ctl_ccch_mode_conf *conf;
650
651         if (msgb_l3len(msg) < sizeof(*conf)) {
652                 LOGP(DL1C, LOGL_ERROR, "CCCH MODE CONF: MSG too short %u\n",
653                         msgb_l3len(msg));
654                 return -1;
655         }
656
657         conf = (struct l1ctl_ccch_mode_conf *) msg->l1h;
658
659         LOGP(DL1C, LOGL_INFO, "CCCH MODE CONF: mode=%u\n", conf->ccch_mode);
660
661         mc.ccch_mode = conf->ccch_mode;
662         mc.ms = ms;
663         dispatch_signal(SS_L1CTL, S_L1CTL_CCCH_MODE_CONF, &mc);
664
665         return 0;
666 }
667
668 /* Receive L1CTL_TCH_MODE_CONF */
669 static int rx_l1_tch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
670 {
671         struct osmobb_tch_mode_conf mc;
672         struct l1ctl_tch_mode_conf *conf;
673
674         if (msgb_l3len(msg) < sizeof(*conf)) {
675                 LOGP(DL1C, LOGL_ERROR, "TCH MODE CONF: MSG too short %u\n",
676                         msgb_l3len(msg));
677                 return -1;
678         }
679
680         conf = (struct l1ctl_tch_mode_conf *) msg->l1h;
681
682         LOGP(DL1C, LOGL_INFO, "TCH MODE CONF: mode=%u\n", conf->tch_mode);
683
684         mc.tch_mode = conf->tch_mode;
685         mc.ms = ms;
686         dispatch_signal(SS_L1CTL, S_L1CTL_TCH_MODE_CONF, &mc);
687
688         return 0;
689 }
690
691 /* Receive incoming data from L1 using L1CTL format */
692 int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
693 {
694         int rc = 0;
695         struct l1ctl_hdr *l1h;
696         struct l1ctl_info_dl *dl;
697
698         if (msgb_l2len(msg) < sizeof(*dl)) {
699                 LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n",
700                         msgb_l2len(msg));
701                 msgb_free(msg);
702                 return -1;
703         }
704
705         l1h = (struct l1ctl_hdr *) msg->l1h;
706
707         /* move the l1 header pointer to point _BEHIND_ l1ctl_hdr,
708            as the l1ctl header is of no interest to subsequent code */
709         msg->l1h = l1h->data;
710
711         switch (l1h->msg_type) {
712         case L1CTL_FBSB_CONF:
713                 rc = rx_l1_fbsb_conf(ms, msg);
714                 msgb_free(msg);
715                 break;
716         case L1CTL_DATA_IND:
717                 rc = rx_ph_data_ind(ms, msg);
718                 break;
719         case L1CTL_DATA_CONF:
720                 rc = rx_ph_data_conf(ms, msg);
721                 break;
722         case L1CTL_RESET_IND:
723         case L1CTL_RESET_CONF:
724                 rc = rx_l1_reset(ms);
725                 msgb_free(msg);
726                 break;
727         case L1CTL_PM_CONF:
728                 rc = rx_l1_pm_conf(ms, msg);
729                 msgb_free(msg);
730                 if (l1h->flags & L1CTL_F_DONE)
731                         dispatch_signal(SS_L1CTL, S_L1CTL_PM_DONE, ms);
732                 break;
733         case L1CTL_RACH_CONF:
734                 rc = rx_l1_rach_conf(ms, msg);
735                 break;
736         case L1CTL_CCCH_MODE_CONF:
737                 rc = rx_l1_ccch_mode_conf(ms, msg);
738                 msgb_free(msg);
739                 break;
740         case L1CTL_TCH_MODE_CONF:
741                 rc = rx_l1_tch_mode_conf(ms, msg);
742                 msgb_free(msg);
743                 break;
744         case L1CTL_SIM_CONF:
745                 rc = rx_l1_sim_conf(ms, msg);
746                 break;
747         default:
748                 LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type);
749                 msgb_free(msg);
750                 break;
751         }
752
753         return rc;
754 }