1 /* Synchronous part of GSM Layer 1: API to Layer2+ */
3 /* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
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.
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.
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.
30 #include <byteorder.h>
32 #include <osmocore/msgb.h>
33 #include <comm/sercomm.h>
35 #include <layer1/sync.h>
36 #include <layer1/async.h>
37 #include <layer1/mframe_sched.h>
38 #include <layer1/tpu_window.h>
40 #include <rf/trf6151.h>
42 #include <l1ctl_proto.h>
44 /* the size we will allocate struct msgb* for HDLC */
46 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_data_ind) + L3_MSG_HEAD)
48 void l1_queue_for_l2(struct msgb *msg)
50 /* forward via serial for now */
51 sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
54 static enum mframe_task chan_nr2mf_task(uint8_t chan_nr)
56 uint8_t cbits = chan_nr >> 3;
62 } else if ((cbits & 0x1e) == 0x02) {
63 lch_idx = cbits & 0x1;
65 } else if ((cbits & 0x1c) == 0x04) {
66 lch_idx = cbits & 0x3;
67 return MF_TASK_SDCCH4_0 + lch_idx;
68 } else if ((cbits & 0x18) == 0x08) {
69 lch_idx = cbits & 0x7;
70 return MF_TASK_SDCCH8_0 + lch_idx;
72 } else if (cbits == 0x10) {
73 /* FIXME: when to do extended BCCH? */
74 return MF_TASK_BCCH_NORM;
75 } else if (cbits == 0x11 || cbits == 0x12) {
76 /* FIXME: how to decide CCCH norm/extd? */
77 return MF_TASK_BCCH_CCCH;
83 static int chan_nr2dchan_type(uint8_t chan_nr)
85 uint8_t cbits = chan_nr >> 3;
88 return GSM_DCHAN_TCH_F;
89 } else if ((cbits & 0x1e) == 0x02) {
90 return GSM_DCHAN_TCH_H;
91 } else if ((cbits & 0x1c) == 0x04) {
92 return GSM_DCHAN_SDCCH_4;
93 } else if ((cbits & 0x18) == 0x08) {
94 return GSM_DCHAN_SDCCH_8;
96 return GSM_DCHAN_UNKNOWN;
99 struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
102 struct l1ctl_hdr *l1h;
104 msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
107 puts("OOPS. Out of buffers...\n");
112 l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
113 l1h->msg_type = msg_type;
116 msg->l1h = (uint8_t *)l1h;
121 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
124 struct l1ctl_info_dl *dl;
125 struct msgb *msg = l1ctl_msgb_alloc(msg_type);
127 dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
128 dl->frame_nr = htonl(fn);
130 dl->band_arfcn = htons(arfcn);
135 /* receive a L1CTL_FBSB_REQ from L23 */
136 static void l1ctl_rx_fbsb_req(struct msgb *msg)
138 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
139 struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
141 if (sizeof(*sync_req) > msg->len) {
142 printf("Short sync msg. %u\n", msg->len);
146 printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
147 ntohs(sync_req->band_arfcn), sync_req->flags);
149 /* reset scheduler and hardware */
152 /* pre-set the CCCH mode */
153 l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
155 printd("Starting FCCH Recognition\n");
156 l1s_fbsb_req(1, sync_req);
159 /* receive a L1CTL_DM_EST_REQ from L23 */
160 static void l1ctl_rx_dm_est_req(struct msgb *msg)
162 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
163 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
164 struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
166 printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
167 ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
169 /* Current limitations */
170 if ((ul->chan_nr & 0x7) > 4) {
171 /* FIXME: Timeslot */
172 puts("We don't support TS > 4 yet\n");
176 if ((chan_nr2mf_task(ul->chan_nr) >= MF_TASK_SDCCH8_4) &&
177 (chan_nr2mf_task(ul->chan_nr) <= MF_TASK_SDCCH8_7)) {
178 /* FIXME: TX while RX prevents SDCCH8 [4..7] */
179 puts("We don't support SDCCH8 [4..7] yet\n");
183 /* configure dedicated channel state */
184 l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
185 l1s.dedicated.tsc = est_req->tsc;
186 l1s.dedicated.tn = ul->chan_nr & 0x7;
187 l1s.dedicated.h = est_req->h;
191 l1s.dedicated.h1.hsn = est_req->h1.hsn;
192 l1s.dedicated.h1.maio = est_req->h1.maio;
193 l1s.dedicated.h1.n = est_req->h1.n;
194 for (i=0; i<est_req->h1.n; i++)
195 l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
197 l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
200 /* figure out which MF tasks to enable */
201 l1a_mftask_set(1 << chan_nr2mf_task(ul->chan_nr));
204 /* receive a L1CTL_DM_FREQ_REQ from L23 */
205 static void l1ctl_rx_dm_freq_req(struct msgb *msg)
207 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
208 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
209 struct l1ctl_dm_freq_req *freq_req =
210 (struct l1ctl_dm_freq_req *) ul->payload;
212 printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
213 ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
215 /* configure dedicated channel state */
216 l1s.dedicated.st_tsc = freq_req->tsc;
217 l1s.dedicated.st_h = freq_req->h;
221 l1s.dedicated.st_h1.hsn = freq_req->h1.hsn;
222 l1s.dedicated.st_h1.maio = freq_req->h1.maio;
223 l1s.dedicated.st_h1.n = freq_req->h1.n;
224 for (i=0; i<freq_req->h1.n; i++)
225 l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
227 l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
230 l1a_freq_req(ntohs(freq_req->fn));
233 /* receive a L1CTL_CRYPTO_REQ from L23 */
234 static void l1ctl_rx_crypto_req(struct msgb *msg)
236 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
237 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
238 struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
239 uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
241 printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len);
243 // for dieter: (cr->alog, cr->key, key_len);
247 /* receive a L1CTL_DM_REL_REQ from L23 */
248 static void l1ctl_rx_dm_rel_req(struct msgb *msg)
250 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
251 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
253 printd("L1CTL_DM_REL_REQ\n");
255 l1s.dedicated.type = GSM_DCHAN_NONE;
258 /* receive a L1CTL_RACH_REQ from L23 */
259 static void l1ctl_rx_param_req(struct msgb *msg)
261 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
262 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
263 struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
265 printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n", par_req->ta,
268 l1s.ta = par_req->ta;
272 /* receive a L1CTL_RACH_REQ from L23 */
273 static void l1ctl_rx_rach_req(struct msgb *msg)
275 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
276 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
277 struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
279 printd("L1CTL_RACH_REQ (ra=0x%02x, fn51=%d, mf_off=%d)\n", rach_req->ra, rach_req->fn51, rach_req->mf_off);
281 l1a_rach_req(rach_req->fn51, rach_req->mf_off, rach_req->ra);
284 /* receive a L1CTL_DATA_REQ from L23 */
285 static void l1ctl_rx_data_req(struct msgb *msg)
287 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
288 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
289 struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
290 struct llist_head *tx_queue;
292 printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
294 msg->l3h = data_ind->data;
295 tx_queue = (ul->link_id & 0x40) ?
296 &l1s.tx_queue[L1S_CHAN_SACCH] :
297 &l1s.tx_queue[L1S_CHAN_MAIN];
299 printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
300 ul, ul->payload, data_ind, data_ind->data, msg->l3h);
302 l1a_txq_msgb_enq(tx_queue, msg);
305 /* receive a L1CTL_PM_REQ from L23 */
306 static void l1ctl_rx_pm_req(struct msgb *msg)
308 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
309 struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
311 switch (pm_req->type) {
314 l1s.pm.range.arfcn_start =
315 ntohs(pm_req->range.band_arfcn_from);
316 l1s.pm.range.arfcn_next =
317 ntohs(pm_req->range.band_arfcn_from);
318 l1s.pm.range.arfcn_end =
319 ntohs(pm_req->range.band_arfcn_to);
320 printf("L1CTL_PM_REQ start=%u end=%u\n",
321 l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
325 l1s_pm_test(1, l1s.pm.range.arfcn_next);
328 /* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
329 void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
331 struct msgb *msg = l1ctl_msgb_alloc(msg_type);
332 struct l1ctl_reset *reset_resp;
333 reset_resp = (struct l1ctl_reset *)
334 msgb_put(msg, sizeof(*reset_resp));
335 reset_resp->type = reset_type;
337 l1_queue_for_l2(msg);
340 /* receive a L1CTL_RESET_REQ from L23 */
341 static void l1ctl_rx_reset_req(struct msgb *msg)
343 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
344 struct l1ctl_reset *reset_req =
345 (struct l1ctl_reset *) l1h->data;
347 switch (reset_req->type) {
348 case L1CTL_RES_T_FULL:
349 printf("L1CTL_RESET_REQ: FULL!\n");
352 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
354 case L1CTL_RES_T_SCHED:
355 printf("L1CTL_RESET_REQ: SCHED!\n");
356 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
357 sched_gsmtime_reset();
360 printf("unknown L1CTL_RESET_REQ type\n");
365 /* Transmit a L1CTL_CCCH_MODE_CONF */
366 static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
368 struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
369 struct l1ctl_ccch_mode_conf *mode_conf;
370 mode_conf = (struct l1ctl_ccch_mode_conf *)
371 msgb_put(msg, sizeof(*mode_conf));
372 mode_conf->ccch_mode = ccch_mode;
374 l1_queue_for_l2(msg);
377 /* receive a L1CTL_CCCH_MODE_REQ from L23 */
378 static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
380 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
381 struct l1ctl_ccch_mode_req *ccch_mode_req =
382 (struct l1ctl_ccch_mode_req *) l1h->data;
383 uint8_t ccch_mode = ccch_mode_req->ccch_mode;
385 /* pre-set the CCCH mode */
386 l1s.serving_cell.ccch_mode = ccch_mode;
389 mframe_disable(MF_TASK_CCCH_COMB);
390 mframe_disable(MF_TASK_CCCH);
392 if (ccch_mode == CCCH_MODE_COMBINED)
393 mframe_enable(MF_TASK_CCCH_COMB);
394 else if (ccch_mode == CCCH_MODE_NON_COMBINED)
395 mframe_enable(MF_TASK_CCCH);
397 l1ctl_tx_ccch_mode_conf(ccch_mode);
400 /* callback from SERCOMM when L2 sends a message to L1 */
401 static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
403 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
408 printf("l1a_l23_rx_cb (%u): ", msg->len);
409 for (i = 0; i < msg->len; i++)
410 printf("%02x ", msg->data[i]);
415 msg->l1h = msg->data;
417 if (sizeof(*l1h) > msg->len) {
418 printf("l1a_l23_cb: Short message. %u\n", msg->len);
422 switch (l1h->msg_type) {
424 l1ctl_rx_fbsb_req(msg);
426 case L1CTL_DM_EST_REQ:
427 l1ctl_rx_dm_est_req(msg);
429 case L1CTL_DM_REL_REQ:
430 l1ctl_rx_dm_rel_req(msg);
432 case L1CTL_PARAM_REQ:
433 l1ctl_rx_param_req(msg);
435 case L1CTL_DM_FREQ_REQ:
436 l1ctl_rx_dm_freq_req(msg);
438 case L1CTL_CRYPTO_REQ:
439 l1ctl_rx_crypto_req(msg);
442 l1ctl_rx_rach_req(msg);
445 l1ctl_rx_data_req(msg);
446 /* we have to keep the msgb, not free it! */
449 l1ctl_rx_pm_req(msg);
451 case L1CTL_RESET_REQ:
452 l1ctl_rx_reset_req(msg);
454 case L1CTL_CCCH_MODE_REQ:
455 l1ctl_rx_ccch_mode_req(msg);
465 void l1a_l23api_init(void)
467 sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);