0560e449c847eada460cd82cb7c34799990eb968
[osmocom-bb.git] / src / target / firmware / layer1 / l23_api.c
1 /* Synchronous part of GSM Layer 1: API to Layer2+ */
2
3 /* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.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 #define DEBUG
24
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <debug.h>
30 #include <byteorder.h>
31
32 #include <osmocom/core/msgb.h>
33 #include <osmocom/gsm/protocol/gsm_04_08.h>
34 #include <comm/sercomm.h>
35
36 #include <layer1/sync.h>
37 #include <layer1/async.h>
38 #include <layer1/mframe_sched.h>
39 #include <layer1/prim.h>
40 #include <layer1/tpu_window.h>
41
42 #include <abb/twl3025.h>
43 #include <rf/trf6151.h>
44
45 #include <l1ctl_proto.h>
46
47 /* the size we will allocate struct msgb* for HDLC */
48 #define L3_MSG_HEAD 4
49 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_data_ind) + L3_MSG_HEAD)
50
51 void l1_queue_for_l2(struct msgb *msg)
52 {
53         /* forward via serial for now */
54         sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
55 }
56
57 enum mf_type {
58         MFNONE,
59         MF51,
60         MF26ODD,
61         MF26EVEN
62 };
63 static uint32_t chan_nr2mf_task_mask(uint8_t chan_nr, uint8_t neigh_mode)
64 {
65         uint8_t cbits = chan_nr >> 3;
66         uint8_t tn = chan_nr & 0x7;
67         uint8_t lch_idx;
68         enum mframe_task master_task = 0;
69         uint32_t neigh_task = 0;
70         enum mf_type multiframe;
71
72         if (cbits == 0x01) {
73                 lch_idx = 0;
74                 master_task = (tn & 1) ? MF_TASK_TCH_F_ODD : MF_TASK_TCH_F_EVEN;
75                 multiframe = (tn & 1) ? MF26ODD : MF26EVEN;
76         } else if ((cbits & 0x1e) == 0x02) {
77                 lch_idx = cbits & 0x1;
78                 master_task = MF_TASK_TCH_H_0 + lch_idx;
79         } else if ((cbits & 0x1c) == 0x04) {
80                 lch_idx = cbits & 0x3;
81                 master_task = MF_TASK_SDCCH4_0 + lch_idx;
82                 multiframe = MF51;
83         } else if ((cbits & 0x18) == 0x08) {
84                 lch_idx = cbits & 0x7;
85                 master_task = MF_TASK_SDCCH8_0 + lch_idx;
86                 multiframe = MF51;
87 #if 0
88         } else if (cbits == 0x10) {
89                 /* FIXME: when to do extended BCCH? */
90                 master_task = MF_TASK_BCCH_NORM;
91         } else if (cbits == 0x11 || cbits == 0x12) {
92                 /* FIXME: how to decide CCCH norm/extd? */
93                 master_task = MF_TASK_BCCH_CCCH;
94 #endif
95         }
96         switch (neigh_mode) {
97         case NEIGH_MODE_PM:
98                 switch (multiframe) {
99                 case MF51:
100                         neigh_task = (1 << MF_TASK_NEIGH_PM51);
101                         break;
102                 case MF26EVEN:
103                         neigh_task = (1 << MF_TASK_NEIGH_PM26E);
104                         break;
105                 case MF26ODD:
106                         neigh_task = (1 << MF_TASK_NEIGH_PM26O);
107                         break;
108                 }
109                 break;
110         }
111         return (1 << master_task) | neigh_task;
112 }
113
114 static int  chan_nr2dchan_type(uint8_t chan_nr)
115 {
116         uint8_t cbits = chan_nr >> 3;
117
118         if (cbits == 0x01) {
119                 return GSM_DCHAN_TCH_F;
120         } else if ((cbits & 0x1e) == 0x02) {
121                 return GSM_DCHAN_TCH_H;
122         } else if ((cbits & 0x1c) == 0x04) {
123                 return GSM_DCHAN_SDCCH_4;
124         } else if ((cbits & 0x18) == 0x08) {
125                 return GSM_DCHAN_SDCCH_8;
126         }
127         return GSM_DCHAN_UNKNOWN;
128 }
129
130 static int chan_nr_is_tch(uint8_t chan_nr)
131 {
132         return ((chan_nr >> 3) == 0x01 ||               /* TCH/F */
133                 ((chan_nr >> 3) & 0x1e) == 0x02);       /* TCH/H */
134 }
135
136 static void audio_set_enabled(int enabled)
137 {
138         twl3025_unit_enable(TWL3025_UNIT_VUL, enabled);
139         twl3025_unit_enable(TWL3025_UNIT_VDL, enabled);
140 }
141
142 struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
143 {
144         struct msgb *msg;
145         struct l1ctl_hdr *l1h;
146
147         msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
148         if (!msg) {
149                 while (1) {
150                         puts("OOPS. Out of buffers...\n");
151                 }
152
153                 return NULL;
154         }
155         l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
156         l1h->msg_type = msg_type;
157         l1h->flags = 0;
158
159         msg->l1h = (uint8_t *)l1h;
160
161         return msg;
162 }
163
164 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
165                               uint16_t arfcn)
166 {
167         struct l1ctl_info_dl *dl;
168         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
169
170         dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
171         dl->frame_nr = htonl(fn);
172         dl->snr = snr;
173         dl->band_arfcn = htons(arfcn);
174
175         return msg;
176 }
177
178 /* receive a L1CTL_FBSB_REQ from L23 */
179 static void l1ctl_rx_fbsb_req(struct msgb *msg)
180 {
181         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
182         struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
183
184         if (sizeof(*sync_req) > msg->len) {
185                 printf("Short sync msg. %u\n", msg->len);
186                 return;
187         }
188
189         printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
190                 ntohs(sync_req->band_arfcn), sync_req->flags);
191
192         /* reset scheduler and hardware */
193         l1s_reset();
194
195         /* pre-set the CCCH mode */
196         l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
197
198         printd("Starting FCCH Recognition\n");
199         l1s_fbsb_req(1, sync_req);
200 }
201
202 /* receive a L1CTL_DM_EST_REQ from L23 */
203 static void l1ctl_rx_dm_est_req(struct msgb *msg)
204 {
205         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
206         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
207         struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
208
209         printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
210                 ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
211
212         /* disable neighbour cell measurement */
213         mframe_disable(MF_TASK_NEIGH_PM51);
214
215         /* configure dedicated channel state */
216         l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
217         l1s.dedicated.tsc  = est_req->tsc;
218         l1s.dedicated.tn   = ul->chan_nr & 0x7;
219         l1s.dedicated.h    = est_req->h;
220
221         if (est_req->h) {
222                 int i;
223                 l1s.dedicated.h1.hsn  = est_req->h1.hsn;
224                 l1s.dedicated.h1.maio = est_req->h1.maio;
225                 l1s.dedicated.h1.n    = est_req->h1.n;
226                 for (i=0; i<est_req->h1.n; i++)
227                         l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
228         } else {
229                 l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
230         }
231
232         /* TCH config */
233         if (chan_nr_is_tch(ul->chan_nr)) {
234                 /* Mode */
235                 l1a_tch_mode_set(est_req->tch_mode);
236
237                 /* Sync */
238                 l1s.tch_sync = 1;       /* can be set without locking */
239
240                 /* Audio path */
241                 audio_set_enabled(est_req->tch_mode != GSM48_CMODE_SIGN);
242         }
243
244         /* figure out which MF tasks to enable */
245         l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM));
246 }
247
248 /* receive a L1CTL_DM_FREQ_REQ from L23 */
249 static void l1ctl_rx_dm_freq_req(struct msgb *msg)
250 {
251         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
252         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
253         struct l1ctl_dm_freq_req *freq_req =
254                         (struct l1ctl_dm_freq_req *) ul->payload;
255
256         printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
257                 ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
258
259         /* configure dedicated channel state */
260         l1s.dedicated.st_tsc  = freq_req->tsc;
261         l1s.dedicated.st_h    = freq_req->h;
262
263         if (freq_req->h) {
264                 int i;
265                 l1s.dedicated.st_h1.hsn  = freq_req->h1.hsn;
266                 l1s.dedicated.st_h1.maio = freq_req->h1.maio;
267                 l1s.dedicated.st_h1.n    = freq_req->h1.n;
268                 for (i=0; i<freq_req->h1.n; i++)
269                         l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
270         } else {
271                 l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
272         }
273
274         l1a_freq_req(ntohs(freq_req->fn));
275 }
276
277 /* receive a L1CTL_CRYPTO_REQ from L23 */
278 static void l1ctl_rx_crypto_req(struct msgb *msg)
279 {
280         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
281         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
282         struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
283         uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
284
285         printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len);
286
287         if (cr->algo && key_len != 8) {
288                 printd("L1CTL_CRYPTO_REQ -> Invalid key\n");
289                 return;
290         }
291
292         dsp_load_ciph_param(cr->algo, cr->key);
293 }
294
295 /* receive a L1CTL_DM_REL_REQ from L23 */
296 static void l1ctl_rx_dm_rel_req(struct msgb *msg)
297 {
298         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
299         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
300
301         printd("L1CTL_DM_REL_REQ\n");
302         l1a_mftask_set(0);
303         l1s.dedicated.type = GSM_DCHAN_NONE;
304         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
305         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
306         l1a_meas_msgb_set(NULL);
307         dsp_load_ciph_param(0, NULL);
308         l1a_tch_mode_set(GSM48_CMODE_SIGN);
309         audio_set_enabled(0);
310         l1s.neigh_pm.n = 0;
311 }
312
313 /* receive a L1CTL_PARAM_REQ from L23 */
314 static void l1ctl_rx_param_req(struct msgb *msg)
315 {
316         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
317         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
318         struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
319
320         printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n", par_req->ta,
321                 par_req->tx_power);
322
323         l1s.ta = par_req->ta;
324         l1s.tx_power = par_req->tx_power;
325 }
326
327 /* receive a L1CTL_RACH_REQ from L23 */
328 static void l1ctl_rx_rach_req(struct msgb *msg)
329 {
330         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
331         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
332         struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
333
334         printd("L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
335                 rach_req->ra, ntohs(rach_req->offset), rach_req->combined);
336
337         l1a_rach_req(ntohs(rach_req->offset), rach_req->combined,
338                 rach_req->ra);
339 }
340
341 /* receive a L1CTL_DATA_REQ from L23 */
342 static void l1ctl_rx_data_req(struct msgb *msg)
343 {
344         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
345         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
346         struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
347         struct llist_head *tx_queue;
348
349         printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
350
351         msg->l3h = data_ind->data;
352         if (ul->link_id & 0x40) {
353                 struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
354                 if (gh->proto_discr == GSM48_PDISC_RR
355                  && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
356                         printd("updating measurement report\n");
357                         l1a_meas_msgb_set(msg);
358                         return;
359                 }
360                 tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
361         } else
362                 tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
363
364         printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
365                 ul, ul->payload, data_ind, data_ind->data, msg->l3h);
366
367         l1a_txq_msgb_enq(tx_queue, msg);
368 }
369
370 /* receive a L1CTL_PM_REQ from L23 */
371 static void l1ctl_rx_pm_req(struct msgb *msg)
372 {
373         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
374         struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
375
376         switch (pm_req->type) {
377         case 1:
378                 l1s.pm.mode = 1;
379                 l1s.pm.range.arfcn_start =
380                                 ntohs(pm_req->range.band_arfcn_from);
381                 l1s.pm.range.arfcn_next =
382                                 ntohs(pm_req->range.band_arfcn_from);
383                 l1s.pm.range.arfcn_end =
384                                 ntohs(pm_req->range.band_arfcn_to);
385                 printf("L1CTL_PM_REQ start=%u end=%u\n",
386                         l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
387                 break;
388         }
389
390         l1s_pm_test(1, l1s.pm.range.arfcn_next);
391 }
392
393 /* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
394 void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
395 {
396         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
397         struct l1ctl_reset *reset_resp;
398         reset_resp = (struct l1ctl_reset *)
399                                 msgb_put(msg, sizeof(*reset_resp));
400         reset_resp->type = reset_type;
401
402         l1_queue_for_l2(msg);
403 }
404
405 /* receive a L1CTL_RESET_REQ from L23 */
406 static void l1ctl_rx_reset_req(struct msgb *msg)
407 {
408         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
409         struct l1ctl_reset *reset_req =
410                                 (struct l1ctl_reset *) l1h->data;
411
412         switch (reset_req->type) {
413         case L1CTL_RES_T_FULL:
414                 printf("L1CTL_RESET_REQ: FULL!\n");
415                 l1s_reset();
416                 l1s_reset_hw();
417                 audio_set_enabled(0);
418                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
419                 break;
420         case L1CTL_RES_T_SCHED:
421                 printf("L1CTL_RESET_REQ: SCHED!\n");
422                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
423                 sched_gsmtime_reset();
424                 break;
425         default:
426                 printf("unknown L1CTL_RESET_REQ type\n");
427                 break;
428         }
429 }
430
431 /* Transmit a L1CTL_CCCH_MODE_CONF */
432 static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
433 {
434         struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
435         struct l1ctl_ccch_mode_conf *mode_conf;
436         mode_conf = (struct l1ctl_ccch_mode_conf *)
437                                 msgb_put(msg, sizeof(*mode_conf));
438         mode_conf->ccch_mode = ccch_mode;
439
440         l1_queue_for_l2(msg);
441 }
442
443 /* receive a L1CTL_CCCH_MODE_REQ from L23 */
444 static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
445 {
446         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
447         struct l1ctl_ccch_mode_req *ccch_mode_req =
448                 (struct l1ctl_ccch_mode_req *) l1h->data;
449         uint8_t ccch_mode = ccch_mode_req->ccch_mode;
450
451         /* pre-set the CCCH mode */
452         l1s.serving_cell.ccch_mode = ccch_mode;
453
454         /* Update task */
455         mframe_disable(MF_TASK_CCCH_COMB);
456         mframe_disable(MF_TASK_CCCH);
457
458         if (ccch_mode == CCCH_MODE_COMBINED)
459                 mframe_enable(MF_TASK_CCCH_COMB);
460         else if (ccch_mode == CCCH_MODE_NON_COMBINED)
461                 mframe_enable(MF_TASK_CCCH);
462
463         l1ctl_tx_ccch_mode_conf(ccch_mode);
464 }
465
466 /* Transmit a L1CTL_TCH_MODE_CONF */
467 static void l1ctl_tx_tch_mode_conf(uint8_t tch_mode)
468 {
469         struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
470         struct l1ctl_tch_mode_conf *mode_conf;
471         mode_conf = (struct l1ctl_tch_mode_conf *)
472                                 msgb_put(msg, sizeof(*mode_conf));
473         mode_conf->tch_mode = tch_mode;
474
475         l1_queue_for_l2(msg);
476 }
477
478 /* receive a L1CTL_TCH_MODE_REQ from L23 */
479 static void l1ctl_rx_tch_mode_req(struct msgb *msg)
480 {
481         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
482         struct l1ctl_tch_mode_req *tch_mode_req =
483                 (struct l1ctl_tch_mode_req *) l1h->data;
484         uint8_t tch_mode = tch_mode_req->tch_mode;
485
486         printd("L1CTL_TCH_MODE_REQ (mode=0x%02x)\n", tch_mode);
487         tch_mode = l1a_tch_mode_set(tch_mode);
488
489         audio_set_enabled(tch_mode != GSM48_CMODE_SIGN);
490
491         l1s.tch_sync = 1; /* Needed for audio to work */
492
493         l1ctl_tx_tch_mode_conf(tch_mode);
494 }
495
496 /* receive a L1CTL_NEIGH_PM_REQ from L23 */
497 static void l1ctl_rx_neigh_pm_req(struct msgb *msg)
498 {
499         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
500         struct l1ctl_neigh_pm_req *pm_req =
501                 (struct l1ctl_neigh_pm_req *) l1h->data;
502         int i;
503
504         /* reset list in order to prevent race condition */
505         l1s.neigh_pm.n = 0; /* atomic */
506         l1s.neigh_pm.second = 0;
507         /* now reset pointer and fill list */
508         l1s.neigh_pm.pos = 0;
509         l1s.neigh_pm.running = 0;
510         for (i = 0; i < pm_req->n; i++)
511                 l1s.neigh_pm.band_arfcn[i] = ntohs(pm_req->band_arfcn[i]);
512         printf("L1CTL_NEIGH_PM_REQ new list with %u entries\n", pm_req->n);
513         l1s.neigh_pm.n = pm_req->n; /* atomic */
514
515         /* on BCCH enable PM on frame 51 */
516         if (l1s.dedicated.type == GSM_DCHAN_NONE)
517                 mframe_enable(MF_TASK_NEIGH_PM51);
518 }
519
520 /* callback from SERCOMM when L2 sends a message to L1 */
521 static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
522 {
523         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
524
525 #if 0
526         {
527                 int i;
528                 printf("l1a_l23_rx_cb (%u): ", msg->len);
529                 for (i = 0; i < msg->len; i++)
530                         printf("%02x ", msg->data[i]);
531                 puts("\n");
532         }
533 #endif
534
535         msg->l1h = msg->data;
536
537         if (sizeof(*l1h) > msg->len) {
538                 printf("l1a_l23_cb: Short message. %u\n", msg->len);
539                 goto exit_msgbfree;
540         }
541
542         switch (l1h->msg_type) {
543         case L1CTL_FBSB_REQ:
544                 l1ctl_rx_fbsb_req(msg);
545                 break;
546         case L1CTL_DM_EST_REQ:
547                 l1ctl_rx_dm_est_req(msg);
548                 break;
549         case L1CTL_DM_REL_REQ:
550                 l1ctl_rx_dm_rel_req(msg);
551                 break;
552         case L1CTL_PARAM_REQ:
553                 l1ctl_rx_param_req(msg);
554                 break;
555         case L1CTL_DM_FREQ_REQ:
556                 l1ctl_rx_dm_freq_req(msg);
557                 break;
558         case L1CTL_CRYPTO_REQ:
559                 l1ctl_rx_crypto_req(msg);
560                 break;
561         case L1CTL_RACH_REQ:
562                 l1ctl_rx_rach_req(msg);
563                 break;
564         case L1CTL_DATA_REQ:
565                 l1ctl_rx_data_req(msg);
566                 /* we have to keep the msgb, not free it! */
567                 goto exit_nofree;
568         case L1CTL_PM_REQ:
569                 l1ctl_rx_pm_req(msg);
570                 break;
571         case L1CTL_RESET_REQ:
572                 l1ctl_rx_reset_req(msg);
573                 break;
574         case L1CTL_CCCH_MODE_REQ:
575                 l1ctl_rx_ccch_mode_req(msg);
576                 break;
577         case L1CTL_TCH_MODE_REQ:
578                 l1ctl_rx_tch_mode_req(msg);
579                 break;
580         case L1CTL_NEIGH_PM_REQ:
581                 l1ctl_rx_neigh_pm_req(msg);
582                 break;
583         }
584
585 exit_msgbfree:
586         msgb_free(msg);
587 exit_nofree:
588         return;
589 }
590
591 void l1a_l23api_init(void)
592 {
593         sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
594 }