blob: fa64e17ba306f249d980e00cbbfd88348d13533d [file] [log] [blame]
Harald Welte0c756eb2018-05-06 16:01:29 +02001/* Osmocom Software Defined E1
2 *
3 * (C) 2018 by Harald Welte <laforge@gnumonks.org>
4 *
5 * Implements ITU-T Rec. G.704 Section 2.3
6 */
7
8#include <stdbool.h>
9#include <stdint.h>
10#include <unistd.h>
11#include <errno.h>
12#include <string.h>
13
14#include <osmocom/core/msgb.h>
15#include <osmocom/core/linuxlist.h>
16#include <osmocom/core/logging.h>
17#include <osmocom/core/fsm.h>
18
19#include "crc4itu.h"
Harald Welte24531ce2018-05-12 16:01:30 +020020#include "osmo_e1f.h"
Harald Welte0c756eb2018-05-06 16:01:29 +020021
22#define S(x) (1 << (x))
23
24/* Frame Alignment Signal (BIT1 may be overwritten with CRC-4) */
25#define G704_E1_FAS 0x1B
26
27static inline bool is_correct_fas(uint8_t bt) {
28 if ((bt & 0x7F) == G704_E1_FAS)
29 return true;
30 else
31 return false;
32}
33
34/* are we in SMF II (true) or I (false) */
Harald Welte24531ce2018-05-12 16:01:30 +020035static inline bool is_smf_II(const struct osmo_e1f_tx_state *tx) {
Harald Welte0c756eb2018-05-06 16:01:29 +020036 if (tx->frame_nr >= 8)
37 return true;
38 return false;
39}
40
41static struct osmo_fsm e1_align_fsm;
Harald Welte24531ce2018-05-12 16:01:30 +020042static void align_fsm_reset(struct osmo_e1f_instance *e1i);
Harald Welte0c756eb2018-05-06 16:01:29 +020043
Harald Welte24531ce2018-05-12 16:01:30 +020044static void notify_user(struct osmo_e1f_instance *e1i, enum osmo_e1f_notify_event evt,
Harald Welte0c756eb2018-05-06 16:01:29 +020045 bool present, void *priv)
46{
47 if (!e1i->notify_cb)
48 return;
49 e1i->notify_cb(e1i, evt, present, priv);
50}
51
52/*! Initialize a (caller-allocated) Osmocom E1 Instance
53 * \param[inout] e1i E1 Instance to be initialized
54 * \returns 0 on success, negative on error */
Harald Welte24531ce2018-05-12 16:01:30 +020055int osmo_e1f_instance_init(struct osmo_e1f_instance *e1i, const char *name, e1_notify_cb cb,
Harald Welte0c756eb2018-05-06 16:01:29 +020056 bool crc4_enabled, void *priv)
57{
58 int i;
59
60 e1i->crc4_enabled = crc4_enabled;
61 e1i->notify_cb = cb;
Harald Welte61a23ea2020-12-19 12:03:37 +010062 e1i->tx.sa4_sa8 = 0x1f;
Harald Welte0c756eb2018-05-06 16:01:29 +020063
64 e1i->priv = priv;
65
66 for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {
Harald Welte24531ce2018-05-12 16:01:30 +020067 struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];
Harald Welte0c756eb2018-05-06 16:01:29 +020068 e1t->ts_nr = i;
69 e1t->inst = e1i;
70 INIT_LLIST_HEAD(&e1t->tx.queue);
71
72 e1t->rx.granularity = 256;
73 }
74
Harald Welte37e23742018-05-11 21:20:23 +020075 e1i->rx.fi = osmo_fsm_inst_alloc(&e1_align_fsm, NULL, e1i, LOGL_DEBUG, name);
Harald Welte0c756eb2018-05-06 16:01:29 +020076 if (!e1i->rx.fi)
77 return -1;
78
Harald Welte24531ce2018-05-12 16:01:30 +020079 osmo_e1f_instance_reset(e1i);
Harald Welte0c756eb2018-05-06 16:01:29 +020080
81 return 0;
82}
83
84/*! stop E1 timeslot; release any pending rx/tx buffers
85 * \param[in] e1t Timeslot which we are to stop, disable and release buffers */
Harald Welte24531ce2018-05-12 16:01:30 +020086void osmo_e1f_ts_reset(struct osmo_e1f_instance_ts *e1t)
Harald Welte0c756eb2018-05-06 16:01:29 +020087{
88 e1t->tx.underruns = 0;
89 msgb_queue_free(&e1t->tx.queue);
90
91 e1t->rx.enabled = false;
92 msgb_free(e1t->rx.msg);
93 e1t->rx.msg = NULL;
Harald Welte8a95fd52018-05-11 21:04:03 +020094
95 osmo_isdnhdlc_rcv_init(&e1t->rx.hdlc, OSMO_HDLC_F_BITREVERSE);
96 //osmo_isdnhdlc_rcv_init(&e1t->rx.hdlc, 0);
97 osmo_isdnhdlc_out_init(&e1t->tx.hdlc, 0);
Harald Welte0c756eb2018-05-06 16:01:29 +020098}
99
100/*! stop E1 instance; stops all timeslots and releases any pending rx/tx buffers
101 * \param[in] e1t E1 instance which we are to stop */
Harald Welte24531ce2018-05-12 16:01:30 +0200102void osmo_e1f_instance_reset(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200103{
104 int i;
105
106 align_fsm_reset(e1i);
107
108 e1i->tx.remote_alarm = false;
109 e1i->tx.crc4_error = false;
110 e1i->tx.frame_nr = 0;
111 e1i->tx.crc4_last_smf = 0;
Harald Weltecdbcff92018-05-12 09:44:03 +0200112 e1i->tx.crc4 = crc4itu_init();
Harald Welte0c756eb2018-05-06 16:01:29 +0200113
114 e1i->rx.frame_nr = 0;
115 memset(&e1i->rx.ts0_history, 0, sizeof(e1i->rx.ts0_history));
116 e1i->rx.ts0_hist_len = 0;
117 e1i->rx.remote_alarm = false;
118 e1i->rx.remote_crc4_error = false;
119 e1i->rx.num_ts0_in_mframe_search = 0;
120
121 for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {
Harald Welte24531ce2018-05-12 16:01:30 +0200122 struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];
123 osmo_e1f_ts_reset(e1t);
Harald Welte0c756eb2018-05-06 16:01:29 +0200124 }
125}
126
127/*! obtain pointer to TS given by instance + timeslot number
128 * \param[in] e1i E1 intance on which we work
129 * \param[in] ts_nr E1 timeslot number (1..31)
130 * \returns pointer to timeslot; NULL on error */
Harald Welte24531ce2018-05-12 16:01:30 +0200131struct osmo_e1f_instance_ts *osmo_e1f_instance_ts(struct osmo_e1f_instance *e1i, uint8_t ts_nr)
Harald Welte0c756eb2018-05-06 16:01:29 +0200132{
133 if (ts_nr == 0 || ts_nr >= ARRAY_SIZE(e1i->ts))
134 return NULL;
135
136 return &e1i->ts[ts_nr];
137}
138
139/*! configure an E1 timeslot
140 * \param[in] e1t Timeslot which we are to configure
141 * \param[in] granularity granularity (buffer size) to use on Rx
142 * \param[in] enable enable (true) or disalble (false) receiving on this TS
Harald Welte8a95fd52018-05-11 21:04:03 +0200143 * \param[in] mode the mode for this timeslot (raw or hdlc)
Harald Welte0c756eb2018-05-06 16:01:29 +0200144 * \return 0 on success; negative on error */
Harald Welte24531ce2018-05-12 16:01:30 +0200145int osmo_e1f_ts_config(struct osmo_e1f_instance_ts *e1t, e1_data_cb cb, unsigned int granularity,
146 bool enable, enum osmo_e1f_ts_mode mode)
Harald Welte0c756eb2018-05-06 16:01:29 +0200147{
148 e1t->rx.data_cb = cb;
149 e1t->rx.enabled = enable;
150 e1t->rx.granularity = granularity;
Harald Welte8a95fd52018-05-11 21:04:03 +0200151 e1t->mode = mode;
Harald Welte0c756eb2018-05-06 16:01:29 +0200152
153 return 0;
154}
155
Harald Welte24531ce2018-05-12 16:01:30 +0200156const struct value_string osmo_e1f_notifv_evt_names[] = {
Harald Welte0c756eb2018-05-06 16:01:29 +0200157 { E1_NTFY_EVT_ALIGN_FRAME, "Aligned to Frame" },
158 { E1_NTFY_EVT_ALIGN_CRC_MFRAME, "Aligned to CRC4-Multiframe" },
159 { E1_NTFY_EVT_CRC_ERROR, "CRC Error detected (local)" },
160 { E1_NTFY_EVT_REMOTE_CRC_ERROR, "CRC Error reported (remote)" },
161 { E1_NTFY_EVT_REMOTE_ALARM, "Remote Alarm condition repoorted" },
162 { 0, NULL }
163};
164
165/***********************************************************************
166 * Transmit Side
167 ***********************************************************************/
168
169/*! Enqueue a message buffer of to-be-transmitted data for a timeslot
170 * \param[in] e1i E1 instance for which to enqueue
171 * \param[in] ts_nr Timeslot number on which data is to be transmitted
172 * \param[in] msg Message buffer storing the to-be-transmitted data
173 * \returns 0 on success; negative in case of error.
174 *
175 * Ownership of \a msg is transferred from caller into this function, but only
176 * in case of successful execution (return 0)!
177 */
Harald Welte24531ce2018-05-12 16:01:30 +0200178void osmo_e1f_ts_enqueue(struct osmo_e1f_instance_ts *e1t, struct msgb *msg)
Harald Welte0c756eb2018-05-06 16:01:29 +0200179{
180 msgb_enqueue(&e1t->tx.queue, msg);
181}
182
183/* obtain a CRC4 bit for the current frame number */
Harald Welte24531ce2018-05-12 16:01:30 +0200184static uint8_t e1_pull_crc4_bit(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200185{
186 /* If CRC-4 is disabled, all CRC bits shall be '1' */
187 if (e1i->crc4_enabled == 0) {
188 return 0x01;
189 } else {
190 /* CRC is transmitted MSB first */
191 switch (e1i->tx.frame_nr % 8) {
192 case 0:
193 return (e1i->tx.crc4_last_smf >> 3) & 1;
194 case 2:
195 return (e1i->tx.crc4_last_smf >> 2) & 1;
196 case 4:
197 return (e1i->tx.crc4_last_smf >> 1) & 1;
198 case 6:
199 return (e1i->tx.crc4_last_smf >> 0) & 1;
200 default:
201 OSMO_ASSERT(0);
202 }
203 }
204}
205
206/* pull a single to-be-transmitted byte for TS0 */
Harald Welte24531ce2018-05-12 16:01:30 +0200207static uint8_t e1_pull_ts0(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200208{
Harald Welte2e7284b2020-12-19 12:05:50 +0100209 uint8_t ret = 0;
Harald Welte0c756eb2018-05-06 16:01:29 +0200210
Harald Welted9a8f9a2020-12-19 12:06:32 +0100211 /* re-set CRC4 at start of sub-multiframe */
212 if (e1i->tx.frame_nr == 0 || e1i->tx.frame_nr == 8) {
213 e1i->tx.crc4_last_smf = e1i->tx.crc4;
214 e1i->tx.crc4 = 0;
215 }
216
Harald Welte0c756eb2018-05-06 16:01:29 +0200217 /* according to Table 5B/G.704 - CRC-4 multiframe structure */
218 if ((e1i->tx.frame_nr % 2) == 0) {
219 /* FAS */
220 ret = G704_E1_FAS | (e1_pull_crc4_bit(e1i) << 7);
221 } else {
222 switch (e1i->tx.frame_nr) {
223 case 1:
224 case 3:
225 case 7:
226 ret = 0x40;
227 break;
228 case 5:
229 case 9:
230 case 11:
231 ret = 0xC0;
232 break;
233 case 13:
234 case 15:
235 ret = 0x40;
Harald Welte6360c072020-12-19 12:33:38 +0100236 if (!e1i->tx.crc4_error)
Harald Welte0c756eb2018-05-06 16:01:29 +0200237 ret |= 0x80;
238 break;
239 }
240 ret |= e1i->tx.sa4_sa8;
241 if (e1i->tx.remote_alarm)
242 ret |= 0x20;
243 }
244
Harald Welte0c756eb2018-05-06 16:01:29 +0200245 /* increment frame number modulo 16 */
246 e1i->tx.frame_nr = (e1i->tx.frame_nr + 1) % 16;
247
248 return ret;
249}
250
251/* pull a single to-be-transmitted byte for TS1..31 */
Harald Welte24531ce2018-05-12 16:01:30 +0200252static uint8_t e1_pull_tsN(struct osmo_e1f_instance_ts *e1t)
Harald Welte0c756eb2018-05-06 16:01:29 +0200253{
254 struct msgb *msg = llist_first_entry_or_null(&e1t->tx.queue, struct msgb, list);
255 uint8_t *cur;
256
257retry:
258 /* if there's no message to transmit */
259 if (!msg) {
260 e1t->tx.underruns++;
261 return 0xFF;
262 }
263 if (msgb_length(msg) <= 0) {
264 llist_del(&msg->list);
265 msgb_free(msg);
266 msg = llist_first_entry_or_null(&e1t->tx.queue, struct msgb, list);
267 goto retry;
268 }
269 cur = msgb_pull(msg, 1);
270 return *cur;
271}
272
273/* update the current in-progress CRC4 value with data from \a out_frame */
Harald Welte24531ce2018-05-12 16:01:30 +0200274static void e1_tx_update_crc4(struct osmo_e1f_instance *e1i, const uint8_t *out_frame)
Harald Welte0c756eb2018-05-06 16:01:29 +0200275{
276 uint8_t ts0;
277
278 ts0 = out_frame[0];
279 /* mask off the C bits */
280 if (is_correct_fas(ts0))
281 ts0 &= 0x7F;
Harald Weltecdbcff92018-05-12 09:44:03 +0200282 e1i->tx.crc4 = crc4itu_update(e1i->tx.crc4, &ts0, 1);
Harald Welte0c756eb2018-05-06 16:01:29 +0200283 /* add the remaining bytes/bits */
Harald Weltecdbcff92018-05-12 09:44:03 +0200284 e1i->tx.crc4 = crc4itu_update(e1i->tx.crc4, out_frame+1, ARRAY_SIZE(e1i->ts)-1);
Harald Welte0c756eb2018-05-06 16:01:29 +0200285}
286
287/*! Pull one to-be-transmitted E1 frame (256bits) from the E1 instance
288 * \param e1i E1 instance for which the frame shall be generated
289 * \param[out] out_frame callee-allocated buffer to which function stores 32 bytes
290 * \returns 0 on success, negative on error */
Harald Welte24531ce2018-05-12 16:01:30 +0200291int osmo_e1f_pull_tx_frame(struct osmo_e1f_instance *e1i, uint8_t *out_frame)
Harald Welte0c756eb2018-05-06 16:01:29 +0200292{
293 int i;
294
Harald Welte9e7a21a2020-12-19 15:41:03 +0100295 if (e1i->tx.ais) {
296 memset(out_frame, 0xff, 32);
297 return 0;
298 }
299
Harald Welte0c756eb2018-05-06 16:01:29 +0200300 /* generate TS0 */
301 out_frame[0] = e1_pull_ts0(e1i);
302
303 /* generate TS1..31 */
304 for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {
Harald Welte24531ce2018-05-12 16:01:30 +0200305 struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];
Harald Welte0c756eb2018-05-06 16:01:29 +0200306 /* get next to-be-transmitted byte from the TS */
307 out_frame[i] = e1_pull_tsN(e1t);
308 }
309 /* update our CRC4 computation */
310 e1_tx_update_crc4(e1i, out_frame);
311
312 return 0;
313}
314
315/***********************************************************************
316 * Receiver Side
317 ***********************************************************************/
318
319/* According to Figure 2 / ITU-T G.706 */
320enum e1_align_state {
321 /* Frame Alignment Search */
322 E1_AS_SEARCH_FRAME,
323 /* CRC multiframe alignment search */
324 E1_AS_SEARCH_CRC_MFRAME,
325 /* monitoring for incorrect frame alignment and error performance using CRC */
326 E1_AS_ALIGNED_CRC_MFRAME,
327 /* no CRC: just frame alignment loss check */
328 E1_AS_ALIGNED_BASIC,
329};
330
331enum e1_align_event {
332 /* received a TS0 octet */
333 E1_AE_RX_TS0,
334 E1_AE_RESET
335};
336
337static const struct value_string e1_align_evt_names[] = {
338 { E1_AE_RX_TS0, "E1_AE_RX_TS0" },
339 { E1_AE_RESET, "E1_AE_RESET" },
340 { 0, NULL }
341};
342
343/* get a TS0 byte from the history. delta 0 == current, delte 1 == previous, ... */
Harald Welte24531ce2018-05-12 16:01:30 +0200344static uint8_t get_ts0_hist(struct osmo_e1f_instance *e1i, uint8_t delta)
Harald Welte0c756eb2018-05-06 16:01:29 +0200345{
346 return e1i->rx.ts0_history[((e1i->rx.frame_nr + 16)-delta) % 16];
347}
348
349/* ITU-T G.706 Section 4.1.1 */
Harald Welte24531ce2018-05-12 16:01:30 +0200350static bool frame_alignment_lost(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200351{
352 if (e1i->rx.frame_nr % 2)
353 return false;
354
355 /* Frame alignment will be assumed to have been lost when three consecutive incorrect
356 * frame alignment signals have been received. */
357 if (!is_correct_fas(get_ts0_hist(e1i, 0)) &&
358 !is_correct_fas(get_ts0_hist(e1i, 2)) &&
359 !is_correct_fas(get_ts0_hist(e1i, 4)))
360 return true;
361 else
362 return false;
363}
364
365/* ITU-T G.706 Section 4.1.2 */
Harald Welte24531ce2018-05-12 16:01:30 +0200366static bool frame_alignment_recovered(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200367{
368 /* two consecutive FAS with one non-FAS interspersed */
369 if (is_correct_fas(get_ts0_hist(e1i, 0)) &&
370 !is_correct_fas(get_ts0_hist(e1i, 1)) &&
371 is_correct_fas(get_ts0_hist(e1i, 2)))
372 return true;
373 else
374 return false;
375}
376
377/* ITU-T G.706 Section 4.2 */
Harald Welte24531ce2018-05-12 16:01:30 +0200378static bool crc_mframe_alignment_achieved(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200379{
380 /* if current TS0 byte is FAS, we cannot detect alignment */
381 if (is_correct_fas(get_ts0_hist(e1i, 0)))
382 return false;
383 if ((get_ts0_hist(e1i, 0) >> 7) == 1 &&
384 (get_ts0_hist(e1i, 2) >> 7) == 1 &&
385 (get_ts0_hist(e1i, 4) >> 7) == 0 &&
386 (get_ts0_hist(e1i, 6) >> 7) == 1 &&
387 (get_ts0_hist(e1i, 8) >> 7) == 0 &&
388 (get_ts0_hist(e1i, 10) >> 7) == 0)
389 return true;
390 else
391 return false;
392}
393
394/* Get the CRC4 that was received from our Rx TS0 history */
Harald Welte24531ce2018-05-12 16:01:30 +0200395static uint8_t crc4_from_ts0_hist(struct osmo_e1f_instance *e1i, bool smf2)
Harald Welte0c756eb2018-05-06 16:01:29 +0200396{
397 uint8_t crc = 0;
398 uint8_t offset = 0;
399
400 if (smf2)
401 offset = 8;
402
Harald Weltecdbcff92018-05-12 09:44:03 +0200403 crc |= (e1i->rx.ts0_history[0+offset] >> 7) << 3;
404 crc |= (e1i->rx.ts0_history[2+offset] >> 7) << 2;
405 crc |= (e1i->rx.ts0_history[4+offset] >> 7) << 1;
406 crc |= (e1i->rx.ts0_history[6+offset] >> 7) << 0;
Harald Welte0c756eb2018-05-06 16:01:29 +0200407
408 return crc;
409}
410
411/* update the current in-progress CRC4 value with data from \a rx_frame */
Harald Welte24531ce2018-05-12 16:01:30 +0200412static void e1_rx_update_crc4(struct osmo_e1f_instance *e1i, const uint8_t *rx_frame)
Harald Welte0c756eb2018-05-06 16:01:29 +0200413{
414 uint8_t ts0;
415
416 ts0 = rx_frame[0];
417 /* mask off the C bits */
418 if (is_correct_fas(ts0))
419 ts0 &= 0x7F;
Harald Weltecdbcff92018-05-12 09:44:03 +0200420 e1i->rx.crc4 = crc4itu_update(e1i->rx.crc4, &ts0, 1);
Harald Welte0c756eb2018-05-06 16:01:29 +0200421 /* add the remaining bytes/bits */
Harald Weltecdbcff92018-05-12 09:44:03 +0200422 e1i->rx.crc4 = crc4itu_update(e1i->rx.crc4, rx_frame+1, ARRAY_SIZE(e1i->ts)-1);
Harald Welte0c756eb2018-05-06 16:01:29 +0200423}
424
425/* FSM State handler */
426static void e1_align_search_frame(struct osmo_fsm_inst *fi, uint32_t event, void *data)
427{
Harald Welte24531ce2018-05-12 16:01:30 +0200428 struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;
Harald Welte0c756eb2018-05-06 16:01:29 +0200429
430 if (frame_alignment_recovered(e1i)) {
431 /* if we detected the 2nd FAS, we must be in FN 2 (or at least FN%2=0 */
432 e1i->rx.frame_nr = 2;
433 notify_user(e1i, E1_NTFY_EVT_ALIGN_FRAME, true, NULL);
434 osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_CRC_MFRAME, 0, 0);
435 }
436}
437
438/* FSM State handler */
439static void e1_align_search_crc_mframe(struct osmo_fsm_inst *fi, uint32_t event, void *data)
440{
Harald Welte24531ce2018-05-12 16:01:30 +0200441 struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;
Harald Welte0c756eb2018-05-06 16:01:29 +0200442
443 if (crc_mframe_alignment_achieved(e1i)) {
444 /* if we detected the 6-bit CRC multiframe signal, we must be in FN 11 */
445 e1i->rx.frame_nr = 11;
446 /* FIXME: "at least two valid CRC multiframe alignment signals can be located within
447 * 8 ms, the time separating two CRC multiframe alignment signals being 2 ms or a
448 * multiple of 2 ms" */
449 notify_user(e1i, E1_NTFY_EVT_ALIGN_CRC_MFRAME, true, NULL);
450 osmo_fsm_inst_state_chg(fi, E1_AS_ALIGNED_CRC_MFRAME, 0, 0);
451 } else {
452 /* if no mframe alignment is established within 8ms (64 frames), fall back */
453 if (e1i->rx.num_ts0_in_mframe_search >= 64) {
454 e1i->rx.num_ts0_in_mframe_search = 0;
455 osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);
456 }
457 e1i->rx.num_ts0_in_mframe_search++;
458 }
459}
460
Harald Welte24531ce2018-05-12 16:01:30 +0200461static void e1_aligned_common(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200462{
463 uint8_t inb = get_ts0_hist(e1i, 0);
464
465 /* All non-FAS frames contain "A" bit in TS0 */
466 if (!is_correct_fas(inb & 0x7F)) {
467 bool old_alarm = e1i->rx.remote_alarm;
468 /* frame not containing the frame alignment signal */
469 if (inb & 0x20)
470 e1i->rx.remote_alarm = true;
471 else
472 e1i->rx.remote_alarm = false;
473 if (old_alarm != e1i->rx.remote_alarm)
474 notify_user(e1i, E1_NTFY_EVT_REMOTE_ALARM, e1i->rx.remote_alarm, NULL);
475 }
476}
477
478/* FSM State handler */
479static void e1_aligned_crc_mframe(struct osmo_fsm_inst *fi, uint32_t event, void *data)
480{
Harald Welte24531ce2018-05-12 16:01:30 +0200481 struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;
Harald Welte0c756eb2018-05-06 16:01:29 +0200482
483 if (frame_alignment_lost(e1i)) {
484 osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);
485 return;
486 }
487
488 if (e1i->crc4_enabled) {
489 uint8_t crc_rx;
490 bool crc4_error;
491
492 /* check if we just received a complete CRC4 */
493 switch (e1i->rx.frame_nr) {
494 case 7:
495 case 15:
496 crc_rx = crc4_from_ts0_hist(e1i, e1i->rx.frame_nr == 15 ? true : false);
497 if (crc_rx != e1i->rx.crc4_last_smf)
498 crc4_error = true;
499 else
500 crc4_error = false;
501 if (crc4_error != e1i->tx.crc4_error) {
502 notify_user(e1i, E1_NTFY_EVT_CRC_ERROR, crc4_error, NULL);
503 e1i->tx.crc4_error = crc4_error;
504 }
505 /* rotate computed CRC4 one further */
506 e1i->rx.crc4_last_smf = e1i->rx.crc4;
Harald Weltecdbcff92018-05-12 09:44:03 +0200507 e1i->rx.crc4 = crc4itu_init();
Harald Welte0c756eb2018-05-06 16:01:29 +0200508 break;
509 default:
510 break;
511 }
512
513 /* check if the remote side reports any CRC errors */
514 switch (e1i->rx.frame_nr) {
515 case 13:
516 case 15:
517 crc4_error = false;
518 if ((get_ts0_hist(e1i, 0) >> 7) == 0)
519 crc4_error = true;
520 if (crc4_error != e1i->rx.remote_crc4_error) {
521 notify_user(e1i, E1_NTFY_EVT_REMOTE_CRC_ERROR, crc4_error, NULL);
522 e1i->rx.remote_crc4_error = crc4_error;
523 }
524 break;
525 }
526 }
527
528 e1_aligned_common(e1i);
529}
530
531/* FSM State handler */
532static void e1_aligned_basic(struct osmo_fsm_inst *fi, uint32_t event, void *data)
533{
Harald Welte24531ce2018-05-12 16:01:30 +0200534 struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;
Harald Welte0c756eb2018-05-06 16:01:29 +0200535
536 if (frame_alignment_lost(e1i)) {
537 osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);
538 return;
539 }
540
541 e1_aligned_common(e1i);
542}
543
544static const struct osmo_fsm_state e1_align_states[] = {
545 [E1_AS_SEARCH_FRAME] = {
546 .name = "SEARCH_FRAME",
547 .in_event_mask = S(E1_AE_RX_TS0),
548 .out_state_mask = S(E1_AS_SEARCH_FRAME) |
549 S(E1_AS_SEARCH_CRC_MFRAME) |
550 S(E1_AS_ALIGNED_BASIC),
551 .action = e1_align_search_frame,
552 },
553 [E1_AS_SEARCH_CRC_MFRAME] = {
554 .name = "SEARCH_CRC_MFRAME",
555 .in_event_mask = S(E1_AE_RX_TS0),
556 .out_state_mask = S(E1_AS_SEARCH_FRAME) |
557 S(E1_AS_SEARCH_CRC_MFRAME) |
558 S(E1_AS_ALIGNED_CRC_MFRAME),
559 .action = e1_align_search_crc_mframe,
560 },
561 [E1_AS_ALIGNED_CRC_MFRAME] = {
562 .name = "ALIGNED_CRC_MFRAME",
563 .in_event_mask = S(E1_AE_RX_TS0),
564 .out_state_mask = S(E1_AS_SEARCH_FRAME) |
565 S(E1_AS_SEARCH_CRC_MFRAME) |
566 S(E1_AS_ALIGNED_CRC_MFRAME),
567 .action = e1_aligned_crc_mframe,
568 },
569 [E1_AS_ALIGNED_BASIC] = {
570 .name = "ALIGNED_BASIC",
571 .in_event_mask = S(E1_AE_RX_TS0),
572 .out_state_mask = S(E1_AS_SEARCH_FRAME),
573 .action = e1_aligned_basic,
574 },
575};
576
577static void e1_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
578{
Harald Welte24531ce2018-05-12 16:01:30 +0200579 struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;
Harald Welte0c756eb2018-05-06 16:01:29 +0200580
581 switch (event) {
582 case E1_AE_RESET:
583 e1i->rx.num_ts0_in_mframe_search = 0;
584 osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);
585 break;
586 }
587}
588
589static struct osmo_fsm e1_align_fsm = {
590 .name = "e1-align",
591 .states = e1_align_states,
592 .num_states = ARRAY_SIZE(e1_align_states),
593 .allstate_event_mask = S(E1_AE_RESET),
594 .allstate_action = e1_allstate,
595 .log_subsys = DLGLOBAL,
596 .event_names = e1_align_evt_names,
597};
598
Harald Welte24531ce2018-05-12 16:01:30 +0200599static void align_fsm_reset(struct osmo_e1f_instance *e1i)
Harald Welte0c756eb2018-05-06 16:01:29 +0200600{
601 osmo_fsm_inst_dispatch(e1i->rx.fi, E1_AE_RESET, NULL);
602}
603
Harald Welte24531ce2018-05-12 16:01:30 +0200604static void e1_rx_hist_add(struct osmo_e1f_instance *e1i, uint8_t inb)
Harald Welte0c756eb2018-05-06 16:01:29 +0200605{
606 e1i->rx.ts0_history[e1i->rx.frame_nr] = inb;
607 if (e1i->rx.ts0_hist_len < 16)
608 e1i->rx.ts0_hist_len++;
609}
610
Harald Welte24531ce2018-05-12 16:01:30 +0200611static void e1_rx_ts0(struct osmo_e1f_instance *e1i, uint8_t inb)
Harald Welte0c756eb2018-05-06 16:01:29 +0200612{
613 /* append just-received byte to the TS0 receive history buffer */
614 e1_rx_hist_add(e1i, inb);
615
616 /* notify the FSM that a new TS0 byte was received */
617 osmo_fsm_inst_dispatch(e1i->rx.fi, E1_AE_RX_TS0, NULL);
618
619 e1i->rx.frame_nr = (e1i->rx.frame_nr + 1) % 16;
620}
621
Harald Welte24531ce2018-05-12 16:01:30 +0200622static void e1_rx_tsN(struct osmo_e1f_instance_ts *e1t, uint8_t inb)
Harald Welte0c756eb2018-05-06 16:01:29 +0200623{
624 struct msgb *msg;
Harald Welte8a95fd52018-05-11 21:04:03 +0200625 int count, rc;
Harald Welte0c756eb2018-05-06 16:01:29 +0200626
627 if (!e1t->rx.enabled)
628 return;
629
630 if (!e1t->rx.msg)
631 e1t->rx.msg = msgb_alloc(e1t->rx.granularity, "E1 Rx");
632 msg = e1t->rx.msg;
633 OSMO_ASSERT(msg);
634
Harald Welte8a95fd52018-05-11 21:04:03 +0200635 switch (e1t->mode) {
Harald Welte24531ce2018-05-12 16:01:30 +0200636 case OSMO_E1F_TS_RAW:
Harald Welte8a95fd52018-05-11 21:04:03 +0200637 /* append byte at end of msgb */
638 msgb_put_u8(msg, inb);
639 /* flush msgb, if full */
640 if (msgb_tailroom(msg) <= 0) {
641 goto flush;
642 }
643 break;
Harald Welte24531ce2018-05-12 16:01:30 +0200644 case OSMO_E1F_TS_HDLC_CRC:
Harald Welte8a95fd52018-05-11 21:04:03 +0200645 rc = osmo_isdnhdlc_decode(&e1t->rx.hdlc, &inb, 1, &count,
646 msgb_data(msg), msgb_tailroom(msg));
647 switch (rc) {
648 case -OSMO_HDLC_FRAMING_ERROR:
649 fprintf(stdout, "Framing Error\n");
650 break;
651 case -OSMO_HDLC_CRC_ERROR:
652 fprintf(stdout, "CRC Error\n");
653 break;
654 case -OSMO_HDLC_LENGTH_ERROR:
655 fprintf(stdout, "Length Error\n");
656 break;
657 case 0:
658 /* no output yet */
659 break;
660 default:
661 msgb_put(msg, rc);
662 goto flush;
663 }
664 break;
Harald Welte0c756eb2018-05-06 16:01:29 +0200665 }
Harald Welte8a95fd52018-05-11 21:04:03 +0200666
667 return;
668flush:
669
670 if (!e1t->rx.data_cb)
671 msgb_free(msg);
672 else
673 e1t->rx.data_cb(e1t, msg);
674 e1t->rx.msg = NULL;
Harald Welte0c756eb2018-05-06 16:01:29 +0200675}
676
677/*! Receive a single E1 frame of 32x8 (=256) bits
678 * \param e1i E1 instance for which the frame was received
679 * \param[in] in_frame caller-provided buffer of 32 octets
680 *
681 * The idea is that whoever calls us will already have done the bit-alignment,
682 * i.e. the first bit of TS0 of the frame will be octet-aligned and hence the
683 * entire 256bit buffer is provided as octet-aligned 32bytes in \a in_frame.
684 */
Harald Welte24531ce2018-05-12 16:01:30 +0200685int osmo_e1f_rx_frame(struct osmo_e1f_instance *e1i, const uint8_t *in_frame)
Harald Welte0c756eb2018-05-06 16:01:29 +0200686{
687 int i;
688
689 e1_rx_update_crc4(e1i, in_frame);
690
691 e1_rx_ts0(e1i, in_frame[0]);
692
693 for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {
Harald Welte24531ce2018-05-12 16:01:30 +0200694 struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];
Harald Welted3941c62018-05-11 16:47:59 +0200695 e1_rx_tsN(e1t, in_frame[i]);
Harald Welte0c756eb2018-05-06 16:01:29 +0200696 }
697
698 return 0;
699}
700
Harald Welte24531ce2018-05-12 16:01:30 +0200701int osmo_e1f_init(void)
Harald Welte0c756eb2018-05-06 16:01:29 +0200702{
703 return osmo_fsm_register(&e1_align_fsm);
704}