blob: a9f15209c3557d3efc065938c91f3dfb2b6519d5 [file] [log] [blame]
Erice29b3c82022-10-27 16:54:09 +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-2022 by Vadim Yanitskiy <axilirator@gmail.com>
7 * Contributions by sysmocom - s.f.m.c. GmbH
8 *
9 * All Rights Reserved
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 */
22
23#include <stdio.h>
24#include <errno.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <stdint.h>
28#include <string.h>
29#include <assert.h>
30
31#include <arpa/inet.h>
32
33#include <osmocom/core/fsm.h>
34#include <osmocom/core/msgb.h>
35#include <osmocom/core/talloc.h>
36#include <osmocom/core/select.h>
37
38#include <osmocom/gsm/gsm0502.h>
39#include <osmocom/gsm/gsm_utils.h>
40#include <osmocom/gsm/protocol/gsm_08_58.h>
41
42#include <osmocom/bb/trxcon/logging.h>
43#include <osmocom/bb/trxcon/l1ctl_server.h>
44#include <osmocom/bb/trxcon/l1ctl_proto.h>
45#include <osmocom/bb/trxcon/trxcon.h>
46
47static const char *arfcn2band_name(uint16_t arfcn)
48{
49 enum gsm_band band;
50
51 if (gsm_arfcn2band_rc(arfcn, &band) < 0)
52 return "(invalid)";
53
54 return gsm_band_name(band);
55}
56
57static struct msgb *l1ctl_alloc_msg(uint8_t msg_type)
58{
59 struct l1ctl_hdr *l1h;
60 struct msgb *msg;
61
62 /**
63 * Each L1CTL message gets its own length pushed in front
64 * before sending. This is why we need this small headroom.
65 */
66 msg = msgb_alloc_headroom(L1CTL_LENGTH + L1CTL_MSG_LEN_FIELD,
67 L1CTL_MSG_LEN_FIELD, "l1ctl_tx_msg");
68 if (!msg) {
69 LOGP(DL1C, LOGL_ERROR, "Failed to allocate memory\n");
70 return NULL;
71 }
72
73 msg->l1h = msgb_put(msg, sizeof(*l1h));
74 l1h = (struct l1ctl_hdr *) msg->l1h;
75 l1h->msg_type = msg_type;
76
77 return msg;
78}
79
80int l1ctl_tx_pm_conf(struct l1ctl_client *l1c, uint16_t band_arfcn,
81 int dbm, int last)
82{
83 struct osmo_fsm_inst *fi = l1c->priv;
84 struct l1ctl_pm_conf *pmc;
85 struct msgb *msg;
86
87 msg = l1ctl_alloc_msg(L1CTL_PM_CONF);
88 if (!msg)
89 return -ENOMEM;
90
91 LOGPFSMSL(fi, DL1C, LOGL_DEBUG,
92 "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_client_send(l1c, msg);
107}
108
109int l1ctl_tx_reset_ind(struct l1ctl_client *l1c, uint8_t type)
110{
111 struct osmo_fsm_inst *fi = l1c->priv;
112 struct msgb *msg;
113 struct l1ctl_reset *res;
114
115 msg = l1ctl_alloc_msg(L1CTL_RESET_IND);
116 if (!msg)
117 return -ENOMEM;
118
119 LOGPFSMSL(fi, DL1C, LOGL_DEBUG, "Send Reset Ind (%u)\n", type);
120
121 res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
122 res->type = type;
123
124 return l1ctl_client_send(l1c, msg);
125}
126
127int l1ctl_tx_reset_conf(struct l1ctl_client *l1c, uint8_t type)
128{
129 struct osmo_fsm_inst *fi = l1c->priv;
130 struct msgb *msg;
131 struct l1ctl_reset *res;
132
133 msg = l1ctl_alloc_msg(L1CTL_RESET_CONF);
134 if (!msg)
135 return -ENOMEM;
136
137 LOGPFSMSL(fi, DL1C, LOGL_DEBUG, "Send Reset Conf (%u)\n", type);
138 res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
139 res->type = type;
140
141 return l1ctl_client_send(l1c, msg);
142}
143
144static struct l1ctl_info_dl *put_dl_info_hdr(struct msgb *msg,
145 const struct l1ctl_info_dl *dl_info)
146{
147 size_t len = sizeof(struct l1ctl_info_dl);
148 struct l1ctl_info_dl *dl = (struct l1ctl_info_dl *) msgb_put(msg, len);
149
150 if (dl_info) /* Copy DL info provided by handler */
151 memcpy(dl, dl_info, len);
152 else /* Init DL info header */
153 memset(dl, 0x00, len);
154
155 return dl;
156}
157
158/* Fill in FBSB payload: BSIC and sync result */
159static struct l1ctl_fbsb_conf *fbsb_conf_make(struct msgb *msg, uint8_t result, uint8_t bsic)
160{
161 struct l1ctl_fbsb_conf *conf = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*conf));
162
163 conf->result = result;
164 conf->bsic = bsic;
165
166 return conf;
167}
168
169int l1ctl_tx_fbsb_fail(struct l1ctl_client *l1c, uint16_t band_arfcn)
170{
171 struct osmo_fsm_inst *fi = l1c->priv;
172 struct l1ctl_info_dl *dl;
173 struct msgb *msg;
174
175 msg = l1ctl_alloc_msg(L1CTL_FBSB_CONF);
176 if (msg == NULL)
177 return -ENOMEM;
178
179 dl = put_dl_info_hdr(msg, NULL);
180
181 /* Fill in current ARFCN */
182 dl->band_arfcn = htons(band_arfcn);
183
184 fbsb_conf_make(msg, 255, 0);
185
186 LOGPFSMSL(fi, DL1C, LOGL_DEBUG, "Send FBSB Conf (timeout)\n");
187
188 return l1ctl_client_send(l1c, msg);
189}
190
191int l1ctl_tx_fbsb_conf(struct l1ctl_client *l1c, uint16_t band_arfcn, uint8_t bsic)
192{
193 struct osmo_fsm_inst *fi = l1c->priv;
194 struct l1ctl_fbsb_conf *conf;
195 struct l1ctl_info_dl *dl;
196 struct msgb *msg;
197
198 msg = l1ctl_alloc_msg(L1CTL_FBSB_CONF);
199 if (msg == NULL)
200 return -ENOMEM;
201
202 dl = put_dl_info_hdr(msg, NULL);
203
204 /* Fill in current ARFCN */
205 dl->band_arfcn = htons(band_arfcn);
206
207 conf = fbsb_conf_make(msg, 0, bsic);
208
209 /* FIXME: set proper value */
210 conf->initial_freq_err = 0;
211
212 LOGPFSMSL(fi, DL1C, LOGL_DEBUG,
213 "Send FBSB Conf (result=%u, bsic=%u)\n",
214 conf->result, conf->bsic);
215
216 return l1ctl_client_send(l1c, msg);
217}
218
219int l1ctl_tx_ccch_mode_conf(struct l1ctl_client *l1c, uint8_t mode)
220{
221 struct l1ctl_ccch_mode_conf *conf;
222 struct msgb *msg;
223
224 msg = l1ctl_alloc_msg(L1CTL_CCCH_MODE_CONF);
225 if (msg == NULL)
226 return -ENOMEM;
227
228 conf = (struct l1ctl_ccch_mode_conf *) msgb_put(msg, sizeof(*conf));
229 conf->ccch_mode = mode;
230
231 return l1ctl_client_send(l1c, msg);
232}
233
234/**
235 * Handles both L1CTL_DATA_IND and L1CTL_TRAFFIC_IND.
236 */
237int l1ctl_tx_dt_ind(struct l1ctl_client *l1c,
238 const struct l1ctl_info_dl *dl_info,
239 const uint8_t *l2, size_t l2_len,
240 bool traffic)
241{
242 struct msgb *msg;
243 uint8_t *msg_l2;
244
245 msg = l1ctl_alloc_msg(traffic ?
246 L1CTL_TRAFFIC_IND : L1CTL_DATA_IND);
247 if (msg == NULL)
248 return -ENOMEM;
249
250 put_dl_info_hdr(msg, dl_info);
251
252 /* Copy the L2 payload if preset */
253 if (l2 && l2_len > 0) {
254 msg_l2 = (uint8_t *) msgb_put(msg, l2_len);
255 memcpy(msg_l2, l2, l2_len);
256 }
257
258 /* Put message to upper layers */
259 return l1ctl_client_send(l1c, msg);
260}
261
262int l1ctl_tx_rach_conf(struct l1ctl_client *l1c,
263 uint16_t band_arfcn, uint32_t fn)
264{
265 struct l1ctl_info_dl *dl;
266 struct msgb *msg;
267
268 msg = l1ctl_alloc_msg(L1CTL_RACH_CONF);
269 if (msg == NULL)
270 return -ENOMEM;
271
272 dl = put_dl_info_hdr(msg, NULL);
273 memset(dl, 0x00, sizeof(*dl));
274
275 dl->band_arfcn = htons(band_arfcn);
276 dl->frame_nr = htonl(fn);
277
278 return l1ctl_client_send(l1c, msg);
279}
280
281
282/**
283 * Handles both L1CTL_DATA_CONF and L1CTL_TRAFFIC_CONF.
284 */
285int l1ctl_tx_dt_conf(struct l1ctl_client *l1c,
286 struct l1ctl_info_dl *data, bool traffic)
287{
288 struct msgb *msg;
289
290 msg = l1ctl_alloc_msg(traffic ?
291 L1CTL_TRAFFIC_CONF : L1CTL_DATA_CONF);
292 if (msg == NULL)
293 return -ENOMEM;
294
295 /* Copy DL frame header from source message */
296 put_dl_info_hdr(msg, data);
297
298 return l1ctl_client_send(l1c, msg);
299}
300
301static enum gsm_phys_chan_config l1ctl_ccch_mode2pchan_config(enum ccch_mode mode)
302{
303 switch (mode) {
304 /* TODO: distinguish extended BCCH */
305 case CCCH_MODE_NON_COMBINED:
306 case CCCH_MODE_NONE:
307 return GSM_PCHAN_CCCH;
308
309 case CCCH_MODE_COMBINED:
310 return GSM_PCHAN_CCCH_SDCCH4;
311 case CCCH_MODE_COMBINED_CBCH:
312 return GSM_PCHAN_CCCH_SDCCH4_CBCH;
313
314 default:
315 LOGP(DL1C, LOGL_NOTICE, "Undandled CCCH mode (%u), "
316 "assuming non-combined configuration\n", mode);
317 return GSM_PCHAN_CCCH;
318 }
319}
320
321static int l1ctl_rx_fbsb_req(struct l1ctl_client *l1c, struct msgb *msg)
322{
323 struct osmo_fsm_inst *fi = l1c->priv;
324 struct l1ctl_fbsb_req *fbsb;
325 int rc = 0;
326
327 fbsb = (struct l1ctl_fbsb_req *) msg->l1h;
328 if (msgb_l1len(msg) < sizeof(*fbsb)) {
329 LOGPFSMSL(fi, DL1C, LOGL_ERROR,
330 "MSG too short FBSB Req: %u\n",
331 msgb_l1len(msg));
332 rc = -EINVAL;
333 goto exit;
334 }
335
336 struct trxcon_param_fbsb_search_req req = {
337 .pchan_config = l1ctl_ccch_mode2pchan_config(fbsb->ccch_mode),
Eric847de6d2022-10-27 16:54:53 +0200338 .timeout_ms = 2000,
Erice29b3c82022-10-27 16:54:09 +0200339 .band_arfcn = ntohs(fbsb->band_arfcn),
340 };
341
342 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
343 "Received FBSB request (%s %d, timeout %u ms)\n",
344 arfcn2band_name(req.band_arfcn),
345 req.band_arfcn & ~ARFCN_FLAG_MASK,
346 req.timeout_ms);
347
348 osmo_fsm_inst_dispatch(fi, TRXCON_EV_FBSB_SEARCH_REQ, &req);
349
350exit:
351 msgb_free(msg);
352 return rc;
353}
354
355static int l1ctl_rx_pm_req(struct l1ctl_client *l1c, struct msgb *msg)
356{
357 struct osmo_fsm_inst *fi = l1c->priv;
358 struct l1ctl_pm_req *pmr;
359 int rc = 0;
360
361 pmr = (struct l1ctl_pm_req *) msg->l1h;
362 if (msgb_l1len(msg) < sizeof(*pmr)) {
363 LOGPFSMSL(fi, DL1C, LOGL_ERROR,
364 "MSG too short PM Req: %u\n",
365 msgb_l1len(msg));
366 rc = -EINVAL;
367 goto exit;
368 }
369
370 struct trxcon_param_full_power_scan_req req = {
371 .band_arfcn_start = ntohs(pmr->range.band_arfcn_from),
372 .band_arfcn_stop = ntohs(pmr->range.band_arfcn_to),
373 };
374
375 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
376 "Received power measurement request (%s: %d -> %d)\n",
377 arfcn2band_name(req.band_arfcn_start),
378 req.band_arfcn_start & ~ARFCN_FLAG_MASK,
379 req.band_arfcn_stop & ~ARFCN_FLAG_MASK);
380
381 osmo_fsm_inst_dispatch(fi, TRXCON_EV_FULL_POWER_SCAN_REQ, &req);
382
383exit:
384 msgb_free(msg);
385 return rc;
386}
387
388static int l1ctl_rx_reset_req(struct l1ctl_client *l1c, struct msgb *msg)
389{
390 struct osmo_fsm_inst *fi = l1c->priv;
391 struct l1ctl_reset *res;
392 int rc = 0;
393
394 res = (struct l1ctl_reset *) msg->l1h;
395 if (msgb_l1len(msg) < sizeof(*res)) {
396 LOGPFSMSL(fi, DL1C, LOGL_ERROR,
397 "MSG too short Reset Req: %u\n",
398 msgb_l1len(msg));
399 rc = -EINVAL;
400 goto exit;
401 }
402
403 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
404 "Received reset request (%u)\n", res->type);
405
406 switch (res->type) {
407 case L1CTL_RES_T_FULL:
408 osmo_fsm_inst_dispatch(fi, TRXCON_EV_RESET_FULL_REQ, NULL);
409 break;
410 case L1CTL_RES_T_SCHED:
411 osmo_fsm_inst_dispatch(fi, TRXCON_EV_RESET_SCHED_REQ, NULL);
412 break;
413 default:
414 LOGPFSMSL(fi, DL1C, LOGL_ERROR,
415 "Unknown L1CTL_RESET_REQ type\n");
416 goto exit;
417 }
418
419 /* Confirm */
420 rc = l1ctl_tx_reset_conf(l1c, res->type);
421
422exit:
423 msgb_free(msg);
424 return rc;
425}
426
427static int l1ctl_rx_echo_req(struct l1ctl_client *l1c, struct msgb *msg)
428{
429 struct osmo_fsm_inst *fi = l1c->priv;
430 struct l1ctl_hdr *l1h;
431
432 LOGPFSMSL(fi, DL1C, LOGL_NOTICE, "Recv Echo Req\n");
433 LOGPFSMSL(fi, DL1C, LOGL_NOTICE, "Send Echo Conf\n");
434
435 /* Nothing to do, just send it back */
436 l1h = (struct l1ctl_hdr *) msg->l1h;
437 l1h->msg_type = L1CTL_ECHO_CONF;
438 msg->data = msg->l1h;
439
440 return l1ctl_client_send(l1c, msg);
441}
442
443static int l1ctl_rx_ccch_mode_req(struct l1ctl_client *l1c, struct msgb *msg)
444{
445 struct osmo_fsm_inst *fi = l1c->priv;
446 struct l1ctl_ccch_mode_req *mode_req;
447 int rc;
448
449 mode_req = (struct l1ctl_ccch_mode_req *)msg->l1h;
450 if (msgb_l1len(msg) < sizeof(*mode_req)) {
451 LOGPFSMSL(fi, DL1C, LOGL_ERROR,
452 "MSG too short Reset Req: %u\n",
453 msgb_l1len(msg));
454 rc = -EINVAL;
455 goto exit;
456 }
457
458 LOGPFSMSL(fi, DL1C, LOGL_NOTICE, "Received CCCH mode request (%u)\n",
459 mode_req->ccch_mode); /* TODO: add value-string for ccch_mode */
460
461 struct trxcon_param_set_ccch_tch_mode_req req = {
462 /* Choose corresponding channel combination */
463 .mode = l1ctl_ccch_mode2pchan_config(mode_req->ccch_mode),
464 };
465
466 rc = osmo_fsm_inst_dispatch(fi, TRXCON_EV_SET_CCCH_MODE_REQ, &req);
467 if (rc == 0 && req.applied)
468 l1ctl_tx_ccch_mode_conf(l1c, mode_req->ccch_mode);
469
470exit:
471 msgb_free(msg);
472 return rc;
473}
474
475static int l1ctl_rx_rach_req(struct l1ctl_client *l1c, struct msgb *msg, bool is_11bit)
476{
477 struct trxcon_param_tx_access_burst_req req;
478 struct osmo_fsm_inst *fi = l1c->priv;
479 struct l1ctl_info_ul *ul;
480
481 ul = (struct l1ctl_info_ul *) msg->l1h;
482
483 if (is_11bit) {
484 const struct l1ctl_ext_rach_req *rr = (void *)ul->payload;
485
486 req = (struct trxcon_param_tx_access_burst_req) {
487 .offset = ntohs(rr->offset),
488 .synch_seq = rr->synch_seq,
489 .ra = ntohs(rr->ra11),
490 .is_11bit = true,
491 };
492
493 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
494 "Received 11-bit RACH request "
495 "(offset=%u, synch_seq=%u, ra11=0x%02hx)\n",
496 req.offset, req.synch_seq, req.ra);
497 } else {
498 const struct l1ctl_rach_req *rr = (void *)ul->payload;
499
500 req = (struct trxcon_param_tx_access_burst_req) {
501 .offset = ntohs(rr->offset),
502 .ra = rr->ra,
503 };
504
505 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
506 "Received 8-bit RACH request "
507 "(offset=%u, ra=0x%02x)\n", req.offset, req.ra);
508 }
509
510 /* The controlling L1CTL side always does include the UL info header,
511 * but may leave it empty. We assume RACH is on TS0 in this case. */
512 if (ul->chan_nr == 0x00) {
513 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
514 "The UL info header is empty, assuming RACH is on TS0\n");
515 req.chan_nr = RSL_CHAN_RACH;
516 req.link_id = 0x00;
517 } else {
518 req.chan_nr = ul->chan_nr;
519 req.link_id = ul->link_id;
520 }
521
522 osmo_fsm_inst_dispatch(fi, TRXCON_EV_TX_ACCESS_BURST_REQ, &req);
523
524 msgb_free(msg);
525 return 0;
526}
527
528static int l1ctl_proc_est_req_h0(struct osmo_fsm_inst *fi,
529 struct trxcon_param_dedicated_establish_req *req,
530 const struct l1ctl_h0 *h)
531{
532 req->h0.band_arfcn = ntohs(h->band_arfcn);
533
534 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
535 "L1CTL_DM_EST_REQ indicates single ARFCN %s %u\n",
536 arfcn2band_name(req->h0.band_arfcn),
537 req->h0.band_arfcn & ~ARFCN_FLAG_MASK);
538
539 return 0;
540}
541
542static int l1ctl_proc_est_req_h1(struct osmo_fsm_inst *fi,
543 struct trxcon_param_dedicated_establish_req *req,
544 const struct l1ctl_h1 *h)
545{
546 unsigned int i;
547
548 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
549 "L1CTL_DM_EST_REQ indicates a Frequency "
550 "Hopping (hsn=%u, maio=%u, chans=%u) channel\n",
551 h->hsn, h->maio, h->n);
552
553 /* No channels?!? */
554 if (!h->n) {
555 LOGPFSMSL(fi, DL1C, LOGL_ERROR,
556 "No channels in mobile allocation?!?\n");
557 return -EINVAL;
558 } else if (h->n > ARRAY_SIZE(h->ma)) {
559 LOGPFSMSL(fi, DL1C, LOGL_ERROR,
560 "More than 64 channels in mobile allocation?!?\n");
561 return -EINVAL;
562 }
563
564 /* Convert from network to host byte order */
565 for (i = 0; i < h->n; i++)
566 req->h1.ma[i] = ntohs(h->ma[i]);
567 req->h1.n = h->n;
568 req->h1.hsn = h->hsn;
569 req->h1.maio = h->maio;
570
571 return 0;
572}
573
574static int l1ctl_rx_dm_est_req(struct l1ctl_client *l1c, struct msgb *msg)
575{
576 struct osmo_fsm_inst *fi = l1c->priv;
577 struct l1ctl_dm_est_req *est_req;
578 struct l1ctl_info_ul *ul;
579 int rc;
580
581 ul = (struct l1ctl_info_ul *) msg->l1h;
582 est_req = (struct l1ctl_dm_est_req *) ul->payload;
583
584 struct trxcon_param_dedicated_establish_req req = {
585 .chan_nr = ul->chan_nr,
586 .tch_mode = est_req->tch_mode,
587 .tsc = est_req->tsc,
588 .hopping = est_req->h,
589 };
590
591 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
592 "Received L1CTL_DM_EST_REQ "
593 "(tn=%u, chan_nr=0x%02x, tsc=%u, tch_mode=0x%02x)\n",
594 req.chan_nr & 0x07, req.chan_nr, req.tsc, req.tch_mode);
595
596 /* Frequency hopping? */
597 if (est_req->h)
598 rc = l1ctl_proc_est_req_h1(fi, &req, &est_req->h1);
599 else /* Single ARFCN */
600 rc = l1ctl_proc_est_req_h0(fi, &req, &est_req->h0);
601 if (rc)
602 goto exit;
603
604 osmo_fsm_inst_dispatch(fi, TRXCON_EV_DEDICATED_ESTABLISH_REQ, &req);
605
606exit:
607 msgb_free(msg);
608 return rc;
609}
610
611static int l1ctl_rx_dm_rel_req(struct l1ctl_client *l1c, struct msgb *msg)
612{
613 struct osmo_fsm_inst *fi = l1c->priv;
614
615 LOGPFSMSL(fi, DL1C, LOGL_NOTICE, "Received L1CTL_DM_REL_REQ\n");
616
617 osmo_fsm_inst_dispatch(fi, TRXCON_EV_DEDICATED_RELEASE_REQ, NULL);
618
619 msgb_free(msg);
620 return 0;
621}
622
623/**
624 * Handles both L1CTL_DATA_REQ and L1CTL_TRAFFIC_REQ.
625 */
626static int l1ctl_rx_dt_req(struct l1ctl_client *l1c,
627 struct msgb *msg, bool traffic)
628{
629 struct osmo_fsm_inst *fi = l1c->priv;
630 struct l1ctl_info_ul *ul;
631
632 /* Extract UL frame header */
633 ul = (struct l1ctl_info_ul *) msg->l1h;
634 msg->l2h = ul->payload;
635
636 struct trxcon_param_tx_traffic_data_req req = {
637 .chan_nr = ul->chan_nr,
638 .link_id = ul->link_id & 0x40,
639 .data_len = msgb_l2len(msg),
640 .data = ul->payload,
641 };
642
643 LOGPFSMSL(fi, DL1D, LOGL_DEBUG,
644 "Recv %s Req (chan_nr=0x%02x, link_id=0x%02x, len=%zu)\n",
645 traffic ? "TRAFFIC" : "DATA", req.chan_nr, req.link_id, req.data_len);
646
647 switch (fi->state) {
648 case TRXCON_ST_DEDICATED:
649 if (traffic)
650 osmo_fsm_inst_dispatch(fi, TRXCON_EV_TX_TRAFFIC_REQ, &req);
651 else
652 osmo_fsm_inst_dispatch(fi, TRXCON_EV_TX_DATA_REQ, &req);
653 break;
654 default:
655 if (!traffic && req.link_id == 0x40) /* only for SACCH */
656 osmo_fsm_inst_dispatch(fi, TRXCON_EV_UPDATE_SACCH_CACHE_REQ, &req);
657 /* TODO: log an error about uhnandled DATA.req / TRAFFIC.req */
658 }
659
660 msgb_free(msg);
661 return 0;
662}
663
664static int l1ctl_rx_param_req(struct l1ctl_client *l1c, struct msgb *msg)
665{
666 struct osmo_fsm_inst *fi = l1c->priv;
667 struct l1ctl_par_req *par_req;
668 struct l1ctl_info_ul *ul;
669
670 ul = (struct l1ctl_info_ul *) msg->l1h;
671 par_req = (struct l1ctl_par_req *) ul->payload;
672
673 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
674 "Received L1CTL_PARAM_REQ (ta=%d, tx_power=%u)\n",
675 par_req->ta, par_req->tx_power);
676
677 struct trxcon_param_set_phy_config_req req = {
678 .type = TRXCON_PHY_CFGT_TX_PARAMS,
679 .tx_params = {
680 .timing_advance = par_req->ta,
681 .tx_power = par_req->tx_power,
682 }
683 };
684
685 osmo_fsm_inst_dispatch(fi, TRXCON_EV_SET_PHY_CONFIG_REQ, &req);
686
687 msgb_free(msg);
688 return 0;
689}
690
691static int l1ctl_rx_tch_mode_req(struct l1ctl_client *l1c, struct msgb *msg)
692{
693 struct osmo_fsm_inst *fi = l1c->priv;
694 struct l1ctl_tch_mode_req *mode_req;
695 int rc;
696
697 mode_req = (struct l1ctl_tch_mode_req *)msg->l1h;
698
699 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
700 "Received L1CTL_TCH_MODE_REQ (tch_mode=%u, audio_mode=%u)\n",
701 mode_req->tch_mode, mode_req->audio_mode);
702
703 /* TODO: do we need to care about audio_mode? */
704
705 struct trxcon_param_set_ccch_tch_mode_req req = {
706 .mode = mode_req->tch_mode,
707 };
708 if (mode_req->tch_mode == GSM48_CMODE_SPEECH_AMR) {
709 req.amr.start_codec = mode_req->amr.start_codec;
710 req.amr.codecs_bitmask = mode_req->amr.codecs_bitmask;
711 }
712
713 rc = osmo_fsm_inst_dispatch(fi, TRXCON_EV_SET_TCH_MODE_REQ, &req);
714 if (rc != 0 || !req.applied) {
715 talloc_free(msg);
716 return rc;
717 }
718
719 /* Re-use the original message as confirmation */
720 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
721 l1h->msg_type = L1CTL_TCH_MODE_CONF;
722
723 return l1ctl_client_send(l1c, msg);
724}
725
726static int l1ctl_rx_crypto_req(struct l1ctl_client *l1c, struct msgb *msg)
727{
728 struct osmo_fsm_inst *fi = l1c->priv;
729 struct l1ctl_crypto_req *cr;
730 struct l1ctl_info_ul *ul;
731
732 ul = (struct l1ctl_info_ul *) msg->l1h;
733 cr = (struct l1ctl_crypto_req *) ul->payload;
734
735 struct trxcon_param_crypto_req req = {
736 .chan_nr = ul->chan_nr,
737 .a5_algo = cr->algo,
738 .key_len = cr->key_len,
739 .key = cr->key,
740 };
741
742 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
743 "L1CTL_CRYPTO_REQ (algo=A5/%u, key_len=%u)\n",
744 req.a5_algo, req.key_len);
745
746 osmo_fsm_inst_dispatch(fi, TRXCON_EV_CRYPTO_REQ, &req);
747
748 msgb_free(msg);
749 return 0;
750}
751
752int l1ctl_rx_cb(struct l1ctl_client *l1c, struct msgb *msg)
753{
754 struct osmo_fsm_inst *fi = l1c->priv;
755 struct l1ctl_hdr *l1h;
756
757 l1h = (struct l1ctl_hdr *) msg->l1h;
758 msg->l1h = l1h->data;
759
760 switch (l1h->msg_type) {
761 case L1CTL_FBSB_REQ:
762 return l1ctl_rx_fbsb_req(l1c, msg);
763 case L1CTL_PM_REQ:
764 return l1ctl_rx_pm_req(l1c, msg);
765 case L1CTL_RESET_REQ:
766 return l1ctl_rx_reset_req(l1c, msg);
767 case L1CTL_ECHO_REQ:
768 return l1ctl_rx_echo_req(l1c, msg);
769 case L1CTL_CCCH_MODE_REQ:
770 return l1ctl_rx_ccch_mode_req(l1c, msg);
771 case L1CTL_RACH_REQ:
772 return l1ctl_rx_rach_req(l1c, msg, false);
773 case L1CTL_EXT_RACH_REQ:
774 return l1ctl_rx_rach_req(l1c, msg, true);
775 case L1CTL_DM_EST_REQ:
776 return l1ctl_rx_dm_est_req(l1c, msg);
777 case L1CTL_DM_REL_REQ:
778 return l1ctl_rx_dm_rel_req(l1c, msg);
779 case L1CTL_DATA_REQ:
780 return l1ctl_rx_dt_req(l1c, msg, false);
781 case L1CTL_TRAFFIC_REQ:
782 return l1ctl_rx_dt_req(l1c, msg, true);
783 case L1CTL_PARAM_REQ:
784 return l1ctl_rx_param_req(l1c, msg);
785 case L1CTL_TCH_MODE_REQ:
786 return l1ctl_rx_tch_mode_req(l1c, msg);
787 case L1CTL_CRYPTO_REQ:
788 return l1ctl_rx_crypto_req(l1c, msg);
789
790 /* Not (yet) handled messages */
791 case L1CTL_NEIGH_PM_REQ:
792 case L1CTL_DATA_TBF_REQ:
793 case L1CTL_TBF_CFG_REQ:
794 case L1CTL_DM_FREQ_REQ:
795 case L1CTL_SIM_REQ:
796 LOGPFSMSL(fi, DL1C, LOGL_NOTICE,
797 "Ignoring unsupported message (type=%u)\n",
798 l1h->msg_type);
799 msgb_free(msg);
800 return -ENOTSUP;
801 default:
802 LOGPFSMSL(fi, DL1C, LOGL_ERROR, "Unknown MSG type %u: %s\n",
803 l1h->msg_type, osmo_hexdump(msgb_data(msg), msgb_length(msg)));
804 msgb_free(msg);
805 return -EINVAL;
806 }
807}