blob: 8853c63296b8d9687ae71f2012e85e1b33630c3b [file] [log] [blame]
Eric Wildd40300e2022-05-07 15:36:47 +02001/*
2 * OsmocomBB <-> SDR connection bridge
3 * GSM L1 control interface handlers
4 *
5 * (C) 2014 by Sylvain Munaut <tnt@246tNt.com>
6 * (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26#include <stdio.h>
27#include <errno.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <stdint.h>
31#include <string.h>
32#include <assert.h>
33
34#include <arpa/inet.h>
35
36#include <osmocom/core/msgb.h>
37#include <osmocom/core/talloc.h>
38#include <osmocom/core/select.h>
39#include <osmocom/gsm/gsm_utils.h>
40#include <osmocom/gsm/protocol/gsm_08_58.h>
41
42#include "logging.h"
43#include "l1ctl_link.h"
44#include "l1ctl_proto.h"
45
46#include "trx_if.h"
47#include "sched_trx.h"
48
49static const char *arfcn2band_name(uint16_t arfcn)
50{
51 enum gsm_band band;
52
53 if (gsm_arfcn2band_rc(arfcn, &band) < 0)
54 return "(invalid)";
55
56 return gsm_band_name(band);
57}
58
59static struct msgb *l1ctl_alloc_msg(uint8_t msg_type)
60{
61 struct l1ctl_hdr *l1h;
62 struct msgb *msg;
63
64 /**
65 * Each L1CTL message gets its own length pushed in front
66 * before sending. This is why we need this small headroom.
67 */
68 msg = msgb_alloc_headroom(L1CTL_LENGTH + L1CTL_MSG_LEN_FIELD,
69 L1CTL_MSG_LEN_FIELD, "l1ctl_tx_msg");
70 if (!msg) {
71 LOGP(DL1C, LOGL_ERROR, "Failed to allocate memory\n");
72 return NULL;
73 }
74
75 msg->l1h = msgb_put(msg, sizeof(*l1h));
76 l1h = (struct l1ctl_hdr *) msg->l1h;
77 l1h->msg_type = msg_type;
78
79 return msg;
80}
81
82int l1ctl_tx_pm_conf(struct l1ctl_link *l1l, uint16_t band_arfcn,
83 int dbm, int last)
84{
85 struct l1ctl_pm_conf *pmc;
86 struct msgb *msg;
87
88 msg = l1ctl_alloc_msg(L1CTL_PM_CONF);
89 if (!msg)
90 return -ENOMEM;
91
92 LOGP(DL1C, LOGL_DEBUG, "Send PM Conf (%s %d = %d dBm)\n",
93 arfcn2band_name(band_arfcn),
94 band_arfcn &~ ARFCN_FLAG_MASK, dbm);
95
96 pmc = (struct l1ctl_pm_conf *) msgb_put(msg, sizeof(*pmc));
97 pmc->band_arfcn = htons(band_arfcn);
98 pmc->pm[0] = dbm2rxlev(dbm);
99 pmc->pm[1] = 0;
100
101 if (last) {
102 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->l1h;
103 l1h->flags |= L1CTL_F_DONE;
104 }
105
106 return l1ctl_link_send(l1l, msg);
107}
108
109int l1ctl_tx_reset_ind(struct l1ctl_link *l1l, uint8_t type)
110{
111 struct msgb *msg;
112 struct l1ctl_reset *res;
113
114 msg = l1ctl_alloc_msg(L1CTL_RESET_IND);
115 if (!msg)
116 return -ENOMEM;
117
118 LOGP(DL1C, LOGL_DEBUG, "Send Reset Ind (%u)\n", type);
119
120 res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
121 res->type = type;
122
123 return l1ctl_link_send(l1l, msg);
124}
125
126int l1ctl_tx_reset_conf(struct l1ctl_link *l1l, uint8_t type)
127{
128 struct msgb *msg;
129 struct l1ctl_reset *res;
130
131 msg = l1ctl_alloc_msg(L1CTL_RESET_CONF);
132 if (!msg)
133 return -ENOMEM;
134
135 LOGP(DL1C, LOGL_DEBUG, "Send Reset Conf (%u)\n", type);
136 res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
137 res->type = type;
138
139 return l1ctl_link_send(l1l, msg);
140}
141
142static struct l1ctl_info_dl *put_dl_info_hdr(struct msgb *msg, struct l1ctl_info_dl *dl_info)
143{
144 size_t len = sizeof(struct l1ctl_info_dl);
145 struct l1ctl_info_dl *dl = (struct l1ctl_info_dl *) msgb_put(msg, len);
146
147 if (dl_info) /* Copy DL info provided by handler */
148 memcpy(dl, dl_info, len);
149 else /* Init DL info header */
150 memset(dl, 0x00, len);
151
152 return dl;
153}
154
155/* Fill in FBSB payload: BSIC and sync result */
156static struct l1ctl_fbsb_conf *fbsb_conf_make(struct msgb *msg, uint8_t result, uint8_t bsic)
157{
158 struct l1ctl_fbsb_conf *conf = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*conf));
159
160 LOGP(DL1C, LOGL_DEBUG, "Send FBSB Conf (result=%u, bsic=%u)\n", result, bsic);
161
162 conf->result = result;
163 conf->bsic = bsic;
164
165 return conf;
166}
167
168int l1ctl_tx_fbsb_conf(struct l1ctl_link *l1l, uint8_t result,
169 struct l1ctl_info_dl *dl_info, uint8_t bsic)
170{
171 struct l1ctl_fbsb_conf *conf;
172 struct msgb *msg;
173
174 msg = l1ctl_alloc_msg(L1CTL_FBSB_CONF);
175 if (msg == NULL)
176 return -ENOMEM;
177
178 put_dl_info_hdr(msg, dl_info);
179 talloc_free(dl_info);
180
181 conf = fbsb_conf_make(msg, result, bsic);
182
183 /* FIXME: set proper value */
184 conf->initial_freq_err = 0;
185
186 /* Ask SCH handler not to send L1CTL_FBSB_CONF anymore */
187 l1l->fbsb_conf_sent = true;
188
189 /* Abort FBSB expire timer */
190 if (osmo_timer_pending(&l1l->fbsb_timer))
191 osmo_timer_del(&l1l->fbsb_timer);
192
193 return l1ctl_link_send(l1l, msg);
194}
195
196int l1ctl_tx_ccch_mode_conf(struct l1ctl_link *l1l, uint8_t mode)
197{
198 struct l1ctl_ccch_mode_conf *conf;
199 struct msgb *msg;
200
201 msg = l1ctl_alloc_msg(L1CTL_CCCH_MODE_CONF);
202 if (msg == NULL)
203 return -ENOMEM;
204
205 conf = (struct l1ctl_ccch_mode_conf *) msgb_put(msg, sizeof(*conf));
206 conf->ccch_mode = mode;
207
208 return l1ctl_link_send(l1l, msg);
209}
210
211/**
212 * Handles both L1CTL_DATA_IND and L1CTL_TRAFFIC_IND.
213 */
214int l1ctl_tx_dt_ind(struct l1ctl_link *l1l, struct l1ctl_info_dl *data,
215 uint8_t *l2, size_t l2_len, bool traffic)
216{
217 struct msgb *msg;
218 uint8_t *msg_l2;
219
220 msg = l1ctl_alloc_msg(traffic ?
221 L1CTL_TRAFFIC_IND : L1CTL_DATA_IND);
222 if (msg == NULL)
223 return -ENOMEM;
224
225 put_dl_info_hdr(msg, data);
226
227 /* Copy the L2 payload if preset */
228 if (l2 && l2_len > 0) {
229 msg_l2 = (uint8_t *) msgb_put(msg, l2_len);
230 memcpy(msg_l2, l2, l2_len);
231 }
232
233 /* Put message to upper layers */
234 return l1ctl_link_send(l1l, msg);
235}
236
237int l1ctl_tx_rach_conf(struct l1ctl_link *l1l,
238 uint16_t band_arfcn, uint32_t fn)
239{
240 struct l1ctl_info_dl *dl;
241 struct msgb *msg;
242
243 msg = l1ctl_alloc_msg(L1CTL_RACH_CONF);
244 if (msg == NULL)
245 return -ENOMEM;
246
247 dl = put_dl_info_hdr(msg, NULL);
248 memset(dl, 0x00, sizeof(*dl));
249
250 dl->band_arfcn = htons(band_arfcn);
251 dl->frame_nr = htonl(fn);
252
253 return l1ctl_link_send(l1l, msg);
254}
255
256
257/**
258 * Handles both L1CTL_DATA_CONF and L1CTL_TRAFFIC_CONF.
259 */
260int l1ctl_tx_dt_conf(struct l1ctl_link *l1l,
261 struct l1ctl_info_dl *data, bool traffic)
262{
263 struct msgb *msg;
264
265 msg = l1ctl_alloc_msg(traffic ?
266 L1CTL_TRAFFIC_CONF : L1CTL_DATA_CONF);
267 if (msg == NULL)
268 return -ENOMEM;
269
270 /* Copy DL frame header from source message */
271 put_dl_info_hdr(msg, data);
272
273 return l1ctl_link_send(l1l, msg);
274}
275
276static enum gsm_phys_chan_config l1ctl_ccch_mode2pchan_config(enum ccch_mode mode)
277{
278 switch (mode) {
279 /* TODO: distinguish extended BCCH */
280 case CCCH_MODE_NON_COMBINED:
281 case CCCH_MODE_NONE:
282 return GSM_PCHAN_CCCH;
283
284 case CCCH_MODE_COMBINED:
285 return GSM_PCHAN_CCCH_SDCCH4;
286 case CCCH_MODE_COMBINED_CBCH:
287 return GSM_PCHAN_CCCH_SDCCH4_CBCH;
288
289 default:
290 LOGP(DL1C, LOGL_NOTICE, "Undandled CCCH mode (%u), "
291 "assuming non-combined configuration\n", mode);
292 return GSM_PCHAN_CCCH;
293 }
294}
295
296/* FBSB expire timer */
297static void fbsb_timer_cb(void *data)
298{
299 struct l1ctl_link *l1l = (struct l1ctl_link *) data;
300 struct l1ctl_info_dl *dl;
301 struct msgb *msg;
302
303 msg = l1ctl_alloc_msg(L1CTL_FBSB_CONF);
304 if (msg == NULL)
305 return;
306
307 LOGP(DL1C, LOGL_NOTICE, "FBSB timer fired for ARFCN %u\n", l1l->trx->band_arfcn &~ ARFCN_FLAG_MASK);
308
309 dl = put_dl_info_hdr(msg, NULL);
310
311 /* Fill in current ARFCN */
312 dl->band_arfcn = htons(l1l->trx->band_arfcn);
313
314 fbsb_conf_make(msg, 255, 0);
315
316 /* Ask SCH handler not to send L1CTL_FBSB_CONF anymore */
317 l1l->fbsb_conf_sent = true;
318
319 l1ctl_link_send(l1l, msg);
320}
321
322static int l1ctl_rx_fbsb_req(struct l1ctl_link *l1l, struct msgb *msg)
323{
324 enum gsm_phys_chan_config ch_config;
325 struct l1ctl_fbsb_req *fbsb;
326 uint16_t band_arfcn;
327 uint16_t timeout;
328 int rc = 0;
329
330 fbsb = (struct l1ctl_fbsb_req *) msg->l1h;
331 if (msgb_l1len(msg) < sizeof(*fbsb)) {
332 LOGP(DL1C, LOGL_ERROR, "MSG too short FBSB Req: %u\n",
333 msgb_l1len(msg));
334 rc = -EINVAL;
335 goto exit;
336 }
337
338 ch_config = l1ctl_ccch_mode2pchan_config(fbsb->ccch_mode);
339 band_arfcn = ntohs(fbsb->band_arfcn);
340 timeout = ntohs(fbsb->timeout);
341
342 LOGP(DL1C, LOGL_NOTICE, "Received FBSB request (%s %d)\n",
343 arfcn2band_name(band_arfcn),
344 band_arfcn &~ ARFCN_FLAG_MASK);
345
346 /* Reset scheduler and clock counter */
347 sched_trx_reset(l1l->trx, true);
348
349 /* Configure a single timeslot */
350 sched_trx_configure_ts(l1l->trx, 0, ch_config);
351
352 /* Ask SCH handler to send L1CTL_FBSB_CONF */
353 l1l->fbsb_conf_sent = false;
354
355 /* Only if current ARFCN differs */
Eric935c8cb2022-06-06 00:48:09 +0200356 if (l1l->trx->band_arfcn != band_arfcn) {
Eric Wildd40300e2022-05-07 15:36:47 +0200357 /* Update current ARFCN */
358 l1l->trx->band_arfcn = band_arfcn;
359
360 /* Tune transceiver to required ARFCN */
361 trx_if_cmd_rxtune(l1l->trx, band_arfcn);
362 trx_if_cmd_txtune(l1l->trx, band_arfcn);
Eric935c8cb2022-06-06 00:48:09 +0200363 }
Eric Wildd40300e2022-05-07 15:36:47 +0200364
365 /* Transceiver might have been powered on before, e.g.
366 * in case of sending L1CTL_FBSB_REQ due to signal loss. */
367 if (!l1l->trx->powered_up)
368 trx_if_cmd_poweron(l1l->trx);
369
370 trx_if_cmd_sync(l1l->trx);
371
372 /* Start FBSB expire timer */
373 l1l->fbsb_timer.data = l1l;
374 l1l->fbsb_timer.cb = fbsb_timer_cb;
375 LOGP(DL1C, LOGL_INFO, "Starting FBSB timer %u ms\n", timeout * GSM_TDMA_FN_DURATION_uS / 1000);
Eric935c8cb2022-06-06 00:48:09 +0200376 osmo_timer_schedule(&l1l->fbsb_timer, 2, timeout * GSM_TDMA_FN_DURATION_uS);
Eric Wildd40300e2022-05-07 15:36:47 +0200377
378exit:
379 msgb_free(msg);
380 return rc;
381}
382
383static int l1ctl_rx_pm_req(struct l1ctl_link *l1l, struct msgb *msg)
384{
385 uint16_t band_arfcn_start, band_arfcn_stop;
386 struct l1ctl_pm_req *pmr;
387 int rc = 0;
388
389 pmr = (struct l1ctl_pm_req *) msg->l1h;
390 if (msgb_l1len(msg) < sizeof(*pmr)) {
391 LOGP(DL1C, LOGL_ERROR, "MSG too short PM Req: %u\n",
392 msgb_l1len(msg));
393 rc = -EINVAL;
394 goto exit;
395 }
396
397 band_arfcn_start = ntohs(pmr->range.band_arfcn_from);
398 band_arfcn_stop = ntohs(pmr->range.band_arfcn_to);
399
400 LOGP(DL1C, LOGL_NOTICE, "Received power measurement "
401 "request (%s: %d -> %d)\n",
402 arfcn2band_name(band_arfcn_start),
403 band_arfcn_start &~ ARFCN_FLAG_MASK,
404 band_arfcn_stop &~ ARFCN_FLAG_MASK);
405
406 /* Send measurement request to transceiver */
407 rc = trx_if_cmd_measure(l1l->trx, band_arfcn_start, band_arfcn_stop);
408
409exit:
410 msgb_free(msg);
411 return rc;
412}
413
414static int l1ctl_rx_reset_req(struct l1ctl_link *l1l, struct msgb *msg)
415{
416 struct l1ctl_reset *res;
417 int rc = 0;
418
419 res = (struct l1ctl_reset *) msg->l1h;
420 if (msgb_l1len(msg) < sizeof(*res)) {
421 LOGP(DL1C, LOGL_ERROR, "MSG too short Reset Req: %u\n",
422 msgb_l1len(msg));
423 rc = -EINVAL;
424 goto exit;
425 }
426
427 LOGP(DL1C, LOGL_NOTICE, "Received reset request (%u)\n",
428 res->type);
429
430 switch (res->type) {
431 case L1CTL_RES_T_FULL:
432 /* TODO: implement trx_if_reset() */
433 trx_if_cmd_poweroff(l1l->trx);
434 trx_if_cmd_echo(l1l->trx);
435
436 /* Fall through */
437 case L1CTL_RES_T_SCHED:
438 sched_trx_reset(l1l->trx, true);
439 break;
440 default:
441 LOGP(DL1C, LOGL_ERROR, "Unknown L1CTL_RESET_REQ type\n");
442 goto exit;
443 }
444
445 /* Confirm */
446 rc = l1ctl_tx_reset_conf(l1l, res->type);
447
448exit:
449 msgb_free(msg);
450 return rc;
451}
452
453static int l1ctl_rx_echo_req(struct l1ctl_link *l1l, struct msgb *msg)
454{
455 struct l1ctl_hdr *l1h;
456
457 LOGP(DL1C, LOGL_NOTICE, "Recv Echo Req\n");
458 LOGP(DL1C, LOGL_NOTICE, "Send Echo Conf\n");
459
460 /* Nothing to do, just send it back */
461 l1h = (struct l1ctl_hdr *) msg->l1h;
462 l1h->msg_type = L1CTL_ECHO_CONF;
463 msg->data = msg->l1h;
464
465 return l1ctl_link_send(l1l, msg);
466}
467
468static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
469{
470 enum gsm_phys_chan_config ch_config;
471 struct l1ctl_ccch_mode_req *req;
472 struct trx_ts *ts;
473 int rc = 0;
474
475 req = (struct l1ctl_ccch_mode_req *) msg->l1h;
476 if (msgb_l1len(msg) < sizeof(*req)) {
477 LOGP(DL1C, LOGL_ERROR, "MSG too short Reset Req: %u\n",
478 msgb_l1len(msg));
479 rc = -EINVAL;
480 goto exit;
481 }
482
483 LOGP(DL1C, LOGL_NOTICE, "Received CCCH mode request (%u)\n",
484 req->ccch_mode); /* TODO: add value-string for ccch_mode */
485
486 /* Make sure that TS0 is allocated and configured */
487 ts = l1l->trx->ts_list[0];
488 if (ts == NULL || ts->mf_layout == NULL) {
489 LOGP(DL1C, LOGL_ERROR, "TS0 is not configured");
490 rc = -EINVAL;
491 goto exit;
492 }
493
494 /* Choose corresponding channel combination */
495 ch_config = l1ctl_ccch_mode2pchan_config(req->ccch_mode);
496
497 /* Do nothing if the current mode matches required */
498 if (ts->mf_layout->chan_config != ch_config)
499 rc = sched_trx_configure_ts(l1l->trx, 0, ch_config);
500
501 /* Confirm reconfiguration */
502 if (!rc)
503 rc = l1ctl_tx_ccch_mode_conf(l1l, req->ccch_mode);
504
505exit:
506 msgb_free(msg);
507 return rc;
508}
509
510static int l1ctl_rx_rach_req(struct l1ctl_link *l1l, struct msgb *msg, bool ext)
511{
512 struct l1ctl_ext_rach_req *ext_req;
513 struct l1ctl_rach_req *req;
514 struct l1ctl_info_ul *ul;
515 struct trx_ts_prim *prim;
516 size_t len;
517 int rc;
518
519 ul = (struct l1ctl_info_ul *) msg->l1h;
520
521 /* Is it extended (11-bit) RACH or not? */
522 if (ext) {
523 ext_req = (struct l1ctl_ext_rach_req *) ul->payload;
524 ext_req->offset = ntohs(ext_req->offset);
525 ext_req->ra11 = ntohs(ext_req->ra11);
526 len = sizeof(*ext_req);
527
528 LOGP(DL1C, LOGL_NOTICE, "Received extended (11-bit) RACH request "
529 "(offset=%u, synch_seq=%u, ra11=0x%02hx)\n",
530 ext_req->offset, ext_req->synch_seq, ext_req->ra11);
531 } else {
532 req = (struct l1ctl_rach_req *) ul->payload;
533 req->offset = ntohs(req->offset);
534 len = sizeof(*req);
535
536 LOGP(DL1C, LOGL_NOTICE, "Received regular (8-bit) RACH request "
537 "(offset=%u, ra=0x%02x)\n", req->offset, req->ra);
538 }
539
540 /* The controlling L1CTL side always does include the UL info header,
541 * but may leave it empty. We assume RACH is on TS0 in this case. */
542 if (ul->chan_nr == 0x00) {
543 LOGP(DL1C, LOGL_NOTICE, "The UL info header is empty, "
544 "assuming RACH is on TS0\n");
545 ul->chan_nr = RSL_CHAN_RACH;
546 }
547
548 /* Init a new primitive */
549 rc = sched_prim_init(l1l->trx, &prim, len, ul->chan_nr, ul->link_id);
550 if (rc)
551 goto exit;
552
553 /**
554 * Push this primitive to the transmit queue.
555 * Indicated timeslot needs to be configured.
556 */
557 rc = sched_prim_push(l1l->trx, prim, ul->chan_nr);
558 if (rc) {
559 talloc_free(prim);
560 goto exit;
561 }
562
563 /* Fill in the payload */
564 memcpy(prim->payload, ul->payload, len);
565
566exit:
567 msgb_free(msg);
568 return rc;
569}
570
571static int l1ctl_proc_est_req_h0(struct trx_instance *trx, struct l1ctl_h0 *h)
572{
573 uint16_t band_arfcn;
574 int rc = 0;
575
576 band_arfcn = ntohs(h->band_arfcn);
577
578 LOGP(DL1C, LOGL_NOTICE, "L1CTL_DM_EST_REQ indicates a single "
579 "ARFCN=%u channel\n", band_arfcn &~ ARFCN_FLAG_MASK);
580
581 /* Do we need to retune? */
582 if (trx->band_arfcn == band_arfcn)
583 return 0;
584
585 /* Tune transceiver to required ARFCN */
586 rc |= trx_if_cmd_rxtune(trx, band_arfcn);
587 rc |= trx_if_cmd_txtune(trx, band_arfcn);
588 if (rc)
589 return rc;
590
591 /* Update current ARFCN */
592 trx->band_arfcn = band_arfcn;
593
594 return 0;
595}
596
597static int l1ctl_proc_est_req_h1(struct trx_instance *trx, struct l1ctl_h1 *h)
598{
599 uint16_t ma[64];
600 int i, rc;
601
602 LOGP(DL1C, LOGL_NOTICE, "L1CTL_DM_EST_REQ indicates a Frequency "
603 "Hopping (hsn=%u, maio=%u, chans=%u) channel\n",
604 h->hsn, h->maio, h->n);
605
606 /* No channels?!? */
607 if (!h->n) {
608 LOGP(DL1C, LOGL_ERROR, "No channels in mobile allocation?!?\n");
609 return -EINVAL;
610 } else if (h->n > ARRAY_SIZE(ma)) {
611 LOGP(DL1C, LOGL_ERROR, "More than 64 channels in mobile allocation?!?\n");
612 return -EINVAL;
613 }
614
615 /* Convert from network to host byte order */
616 for (i = 0; i < h->n; i++)
617 ma[i] = ntohs(h->ma[i]);
618
619 /* Forward hopping parameters to TRX */
620 rc = trx_if_cmd_setfh(trx, h->hsn, h->maio, ma, h->n);
621 if (rc)
622 return rc;
623
624 /**
625 * TODO: update the state of trx_instance somehow
626 * in order to indicate that it is in hopping mode...
627 */
628 return 0;
629}
630
631static int l1ctl_rx_dm_est_req(struct l1ctl_link *l1l, struct msgb *msg)
632{
633 enum gsm_phys_chan_config config;
634 struct l1ctl_dm_est_req *est_req;
635 struct l1ctl_info_ul *ul;
636 struct trx_ts *ts;
637 uint8_t chan_nr, tn;
638 int rc;
639
640 ul = (struct l1ctl_info_ul *) msg->l1h;
641 est_req = (struct l1ctl_dm_est_req *) ul->payload;
642
643 chan_nr = ul->chan_nr;
644 tn = chan_nr & 0x07;
645
646 LOGP(DL1C, LOGL_NOTICE, "Received L1CTL_DM_EST_REQ "
647 "(tn=%u, chan_nr=0x%02x, tsc=%u, tch_mode=0x%02x)\n",
648 tn, chan_nr, est_req->tsc, est_req->tch_mode);
649
650 /* Determine channel config */
651 config = sched_trx_chan_nr2pchan_config(chan_nr);
652 if (config == GSM_PCHAN_NONE) {
653 LOGP(DL1C, LOGL_ERROR, "Couldn't determine channel config\n");
654 rc = -EINVAL;
655 goto exit;
656 }
657
658 /* Frequency hopping? */
659 if (est_req->h)
660 rc = l1ctl_proc_est_req_h1(l1l->trx, &est_req->h1);
661 else /* Single ARFCN */
662 rc = l1ctl_proc_est_req_h0(l1l->trx, &est_req->h0);
663 if (rc)
664 goto exit;
665
666 /* Update TSC (Training Sequence Code) */
667 l1l->trx->tsc = est_req->tsc;
668
669 /* Configure requested TS */
670 rc = sched_trx_configure_ts(l1l->trx, tn, config);
671 ts = l1l->trx->ts_list[tn];
672 if (rc) {
673 rc = -EINVAL;
674 goto exit;
675 }
676
677 /* Deactivate all lchans */
678 sched_trx_deactivate_all_lchans(ts);
679
680 /* Activate only requested lchans */
681 rc = sched_trx_set_lchans(ts, chan_nr, 1, est_req->tch_mode);
682 if (rc) {
683 LOGP(DL1C, LOGL_ERROR, "Couldn't activate requested lchans\n");
684 rc = -EINVAL;
685 goto exit;
686 }
687
688exit:
689 msgb_free(msg);
690 return rc;
691}
692
693static int l1ctl_rx_dm_rel_req(struct l1ctl_link *l1l, struct msgb *msg)
694{
695 LOGP(DL1C, LOGL_NOTICE, "Received L1CTL_DM_REL_REQ, "
696 "switching back to CCCH\n");
697
698 /* Reset scheduler */
699 sched_trx_reset(l1l->trx, false);
700
701 msgb_free(msg);
702 return 0;
703}
704
705/**
706 * Handles both L1CTL_DATA_REQ and L1CTL_TRAFFIC_REQ.
707 */
708static int l1ctl_rx_dt_req(struct l1ctl_link *l1l,
709 struct msgb *msg, bool traffic)
710{
711 struct l1ctl_info_ul *ul;
712 struct trx_ts_prim *prim;
713 uint8_t chan_nr, link_id;
714 size_t payload_len;
715 int rc;
716
717 /* Extract UL frame header */
718 ul = (struct l1ctl_info_ul *) msg->l1h;
719
720 /* Calculate the payload len */
721 msg->l2h = ul->payload;
722 payload_len = msgb_l2len(msg);
723
724 /* Obtain channel description */
725 chan_nr = ul->chan_nr;
726 link_id = ul->link_id & 0x40;
727
728 LOGP(DL1D, LOGL_DEBUG, "Recv %s Req (chan_nr=0x%02x, "
729 "link_id=0x%02x, len=%zu)\n", traffic ? "TRAFFIC" : "DATA",
730 chan_nr, link_id, payload_len);
731
732 /* Init a new primitive */
733 rc = sched_prim_init(l1l->trx, &prim, payload_len,
734 chan_nr, link_id);
735 if (rc)
736 goto exit;
737
738 /* Push this primitive to transmit queue */
739 rc = sched_prim_push(l1l->trx, prim, chan_nr);
740 if (rc) {
741 talloc_free(prim);
742 goto exit;
743 }
744
745 /* Fill in the payload */
746 memcpy(prim->payload, ul->payload, payload_len);
747
748exit:
749 msgb_free(msg);
750 return rc;
751}
752
753static int l1ctl_rx_param_req(struct l1ctl_link *l1l, struct msgb *msg)
754{
755 struct l1ctl_par_req *par_req;
756 struct l1ctl_info_ul *ul;
757
758 ul = (struct l1ctl_info_ul *) msg->l1h;
759 par_req = (struct l1ctl_par_req *) ul->payload;
760
761 LOGP(DL1C, LOGL_NOTICE, "Received L1CTL_PARAM_REQ "
762 "(ta=%d, tx_power=%u)\n", par_req->ta, par_req->tx_power);
763
764 /* Instruct TRX to use new TA value */
765 if (l1l->trx->ta != par_req->ta) {
766 trx_if_cmd_setta(l1l->trx, par_req->ta);
767 l1l->trx->ta = par_req->ta;
768 }
769
770 l1l->trx->tx_power = par_req->tx_power;
771
772 msgb_free(msg);
773 return 0;
774}
775
776static int l1ctl_rx_tch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
777{
778 struct l1ctl_tch_mode_req *req;
779 struct trx_lchan_state *lchan;
780 struct trx_ts *ts;
781 int i;
782
783 req = (struct l1ctl_tch_mode_req *) msg->l1h;
784
785 LOGP(DL1C, LOGL_NOTICE, "Received L1CTL_TCH_MODE_REQ "
786 "(tch_mode=%u, audio_mode=%u)\n", req->tch_mode, req->audio_mode);
787
788 /* Iterate over timeslot list */
789 for (i = 0; i < TRX_TS_COUNT; i++) {
790 /* Timeslot is not allocated */
791 ts = l1l->trx->ts_list[i];
792 if (ts == NULL)
793 continue;
794
795 /* Timeslot is not configured */
796 if (ts->mf_layout == NULL)
797 continue;
798
799 /* Iterate over all allocated lchans */
800 llist_for_each_entry(lchan, &ts->lchans, list) {
801 /* Omit inactive channels */
802 if (!lchan->active)
803 continue;
804
805 /* Set TCH mode */
806 lchan->tch_mode = req->tch_mode;
807 }
808 }
809
810 /* TODO: do we need to care about audio_mode? */
811
812 /* Re-use the original message as confirmation */
813 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
814 l1h->msg_type = L1CTL_TCH_MODE_CONF;
815
816 return l1ctl_link_send(l1l, msg);
817}
818
819static int l1ctl_rx_crypto_req(struct l1ctl_link *l1l, struct msgb *msg)
820{
821 struct l1ctl_crypto_req *req;
822 struct l1ctl_info_ul *ul;
823 struct trx_ts *ts;
824 uint8_t tn;
825 int rc = 0;
826
827 ul = (struct l1ctl_info_ul *) msg->l1h;
828 req = (struct l1ctl_crypto_req *) ul->payload;
829
830 LOGP(DL1C, LOGL_NOTICE, "L1CTL_CRYPTO_REQ (algo=A5/%u, key_len=%u)\n",
831 req->algo, req->key_len);
832
833 /* Determine TS index */
834 tn = ul->chan_nr & 0x7;
835
836 /* Make sure that required TS is allocated and configured */
837 ts = l1l->trx->ts_list[tn];
838 if (ts == NULL || ts->mf_layout == NULL) {
839 LOGP(DL1C, LOGL_ERROR, "TS %u is not configured\n", tn);
840 rc = -EINVAL;
841 goto exit;
842 }
843
844 /* Poke scheduler */
845 rc = sched_trx_start_ciphering(ts, req->algo, req->key, req->key_len);
846 if (rc) {
847 LOGP(DL1C, LOGL_ERROR, "Couldn't configure ciphering\n");
848 rc = -EINVAL;
849 goto exit;
850 }
851
852exit:
853 msgb_free(msg);
854 return rc;
855}
856
857int l1ctl_rx_cb(struct l1ctl_link *l1l, struct msgb *msg)
858{
859 struct l1ctl_hdr *l1h;
860
861 l1h = (struct l1ctl_hdr *) msg->l1h;
862 msg->l1h = l1h->data;
863
864 switch (l1h->msg_type) {
865 case L1CTL_FBSB_REQ:
866 return l1ctl_rx_fbsb_req(l1l, msg);
867 case L1CTL_PM_REQ:
868 return l1ctl_rx_pm_req(l1l, msg);
869 case L1CTL_RESET_REQ:
870 return l1ctl_rx_reset_req(l1l, msg);
871 case L1CTL_ECHO_REQ:
872 return l1ctl_rx_echo_req(l1l, msg);
873 case L1CTL_CCCH_MODE_REQ:
874 return l1ctl_rx_ccch_mode_req(l1l, msg);
875 case L1CTL_RACH_REQ:
876 return l1ctl_rx_rach_req(l1l, msg, false);
877 case L1CTL_EXT_RACH_REQ:
878 return l1ctl_rx_rach_req(l1l, msg, true);
879 case L1CTL_DM_EST_REQ:
880 return l1ctl_rx_dm_est_req(l1l, msg);
881 case L1CTL_DM_REL_REQ:
882 return l1ctl_rx_dm_rel_req(l1l, msg);
883 case L1CTL_DATA_REQ:
884 return l1ctl_rx_dt_req(l1l, msg, false);
885 case L1CTL_TRAFFIC_REQ:
886 return l1ctl_rx_dt_req(l1l, msg, true);
887 case L1CTL_PARAM_REQ:
888 return l1ctl_rx_param_req(l1l, msg);
889 case L1CTL_TCH_MODE_REQ:
890 return l1ctl_rx_tch_mode_req(l1l, msg);
891 case L1CTL_CRYPTO_REQ:
892 return l1ctl_rx_crypto_req(l1l, msg);
893
894 /* Not (yet) handled messages */
895 case L1CTL_NEIGH_PM_REQ:
896 case L1CTL_DATA_TBF_REQ:
897 case L1CTL_TBF_CFG_REQ:
898 case L1CTL_DM_FREQ_REQ:
899 case L1CTL_SIM_REQ:
900 LOGP(DL1C, LOGL_NOTICE, "Ignoring unsupported message "
901 "(type=%u)\n", l1h->msg_type);
902 msgb_free(msg);
903 return -ENOTSUP;
904 default:
905 LOGP(DL1C, LOGL_ERROR, "Unknown MSG type %u: %s\n", l1h->msg_type,
906 osmo_hexdump(msgb_data(msg), msgb_length(msg)));
907 msgb_free(msg);
908 return -EINVAL;
909 }
910}
911
912void l1ctl_shutdown_cb(struct l1ctl_link *l1l)
913{
914 /* Abort FBSB expire timer */
915 if (osmo_timer_pending(&l1l->fbsb_timer))
916 osmo_timer_del(&l1l->fbsb_timer);
917}