1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
4 *
5 * Copyright (C)
6 *	2009	Karsten Keil		<keil@b1-systems.de>
7 *	2002	Wolfgang M��es		<wolfgang@iksw-muees.de>
8 *	2001	Frode Isaksen		<fisaksen@bewan.com>
9 *      2001	Kai Germaschewski	<kai.germaschewski@gmx.de>
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/crc-ccitt.h>
15#include <linux/bitrev.h>
16#include "isdnhdlc.h"
17
18/*-------------------------------------------------------------------*/
19
20MODULE_AUTHOR("Wolfgang M��es <wolfgang@iksw-muees.de>, "
21	      "Frode Isaksen <fisaksen@bewan.com>, "
22	      "Kai Germaschewski <kai.germaschewski@gmx.de>");
23MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
24MODULE_LICENSE("GPL");
25
26/*-------------------------------------------------------------------*/
27
28enum {
29	HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
30	HDLC_GET_DATA, HDLC_FAST_FLAG
31};
32
33enum {
34	HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
35	HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
36	HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
37	HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
38};
39
40void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
41{
42	memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
43	hdlc->state = HDLC_GET_DATA;
44	if (features & HDLC_56KBIT)
45		hdlc->do_adapt56 = 1;
46	if (features & HDLC_BITREVERSE)
47		hdlc->do_bitreverse = 1;
48}
49EXPORT_SYMBOL(isdnhdlc_out_init);
50
51void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
52{
53	memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
54	if (features & HDLC_DCHANNEL) {
55		hdlc->dchannel = 1;
56		hdlc->state = HDLC_SEND_FIRST_FLAG;
57	} else {
58		hdlc->dchannel = 0;
59		hdlc->state = HDLC_SEND_FAST_FLAG;
60		hdlc->ffvalue = 0x7e;
61	}
62	hdlc->cbin = 0x7e;
63	if (features & HDLC_56KBIT) {
64		hdlc->do_adapt56 = 1;
65		hdlc->state = HDLC_SENDFLAG_B0;
66	} else
67		hdlc->data_bits = 8;
68	if (features & HDLC_BITREVERSE)
69		hdlc->do_bitreverse = 1;
70}
71EXPORT_SYMBOL(isdnhdlc_rcv_init);
72
73static int
74check_frame(struct isdnhdlc_vars *hdlc)
75{
76	int status;
77
78	if (hdlc->dstpos < 2)	/* too small - framing error */
79		status = -HDLC_FRAMING_ERROR;
80	else if (hdlc->crc != 0xf0b8)	/* crc error */
81		status = -HDLC_CRC_ERROR;
82	else {
83		/* remove CRC */
84		hdlc->dstpos -= 2;
85		/* good frame */
86		status = hdlc->dstpos;
87	}
88	return status;
89}
90
91/*
92  isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
93
94  The source buffer is scanned for valid HDLC frames looking for
95  flags (01111110) to indicate the start of a frame. If the start of
96  the frame is found, the bit stuffing is removed (0 after 5 1's).
97  When a new flag is found, the complete frame has been received
98  and the CRC is checked.
99  If a valid frame is found, the function returns the frame length
100  excluding the CRC with the bit HDLC_END_OF_FRAME set.
101  If the beginning of a valid frame is found, the function returns
102  the length.
103  If a framing error is found (too many 1s and not a flag) the function
104  returns the length with the bit HDLC_FRAMING_ERROR set.
105  If a CRC error is found the function returns the length with the
106  bit HDLC_CRC_ERROR set.
107  If the frame length exceeds the destination buffer size, the function
108  returns the length with the bit HDLC_LENGTH_ERROR set.
109
110  src - source buffer
111  slen - source buffer length
112  count - number of bytes removed (decoded) from the source buffer
113  dst _ destination buffer
114  dsize - destination buffer size
115  returns - number of decoded bytes in the destination buffer and status
116  flag.
117*/
118int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
119		    int *count, u8 *dst, int dsize)
120{
121	int status = 0;
122
123	static const unsigned char fast_flag[] = {
124		0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
125	};
126
127	static const unsigned char fast_flag_value[] = {
128		0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
129	};
130
131	static const unsigned char fast_abort[] = {
132		0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
133	};
134
135#define handle_fast_flag(h)						\
136	do {								\
137		if (h->cbin == fast_flag[h->bit_shift]) {		\
138			h->ffvalue = fast_flag_value[h->bit_shift];	\
139			h->state = HDLC_FAST_FLAG;			\
140			h->ffbit_shift = h->bit_shift;			\
141			h->bit_shift = 1;				\
142		} else {						\
143			h->state = HDLC_GET_DATA;			\
144			h->data_received = 0;				\
145		}							\
146	} while (0)
147
148#define handle_abort(h)						\
149	do {							\
150		h->shift_reg = fast_abort[h->ffbit_shift - 1];	\
151		h->hdlc_bits1 = h->ffbit_shift - 2;		\
152		if (h->hdlc_bits1 < 0)				\
153			h->hdlc_bits1 = 0;			\
154		h->data_bits = h->ffbit_shift - 1;		\
155		h->state = HDLC_GET_DATA;			\
156		h->data_received = 0;				\
157	} while (0)
158
159	*count = slen;
160
161	while (slen > 0) {
162		if (hdlc->bit_shift == 0) {
163			/* the code is for bitreverse streams */
164			if (hdlc->do_bitreverse == 0)
165				hdlc->cbin = bitrev8(*src++);
166			else
167				hdlc->cbin = *src++;
168			slen--;
169			hdlc->bit_shift = 8;
170			if (hdlc->do_adapt56)
171				hdlc->bit_shift--;
172		}
173
174		switch (hdlc->state) {
175		case STOPPED:
176			return 0;
177		case HDLC_FAST_IDLE:
178			if (hdlc->cbin == 0xff) {
179				hdlc->bit_shift = 0;
180				break;
181			}
182			hdlc->state = HDLC_GET_FLAG_B0;
183			hdlc->hdlc_bits1 = 0;
184			hdlc->bit_shift = 8;
185			break;
186		case HDLC_GET_FLAG_B0:
187			if (!(hdlc->cbin & 0x80)) {
188				hdlc->state = HDLC_GETFLAG_B1A6;
189				hdlc->hdlc_bits1 = 0;
190			} else {
191				if ((!hdlc->do_adapt56) &&
192				    (++hdlc->hdlc_bits1 >= 8) &&
193				    (hdlc->bit_shift == 1))
194					hdlc->state = HDLC_FAST_IDLE;
195			}
196			hdlc->cbin <<= 1;
197			hdlc->bit_shift--;
198			break;
199		case HDLC_GETFLAG_B1A6:
200			if (hdlc->cbin & 0x80) {
201				hdlc->hdlc_bits1++;
202				if (hdlc->hdlc_bits1 == 6)
203					hdlc->state = HDLC_GETFLAG_B7;
204			} else
205				hdlc->hdlc_bits1 = 0;
206			hdlc->cbin <<= 1;
207			hdlc->bit_shift--;
208			break;
209		case HDLC_GETFLAG_B7:
210			if (hdlc->cbin & 0x80) {
211				hdlc->state = HDLC_GET_FLAG_B0;
212			} else {
213				hdlc->state = HDLC_GET_DATA;
214				hdlc->crc = 0xffff;
215				hdlc->shift_reg = 0;
216				hdlc->hdlc_bits1 = 0;
217				hdlc->data_bits = 0;
218				hdlc->data_received = 0;
219			}
220			hdlc->cbin <<= 1;
221			hdlc->bit_shift--;
222			break;
223		case HDLC_GET_DATA:
224			if (hdlc->cbin & 0x80) {
225				hdlc->hdlc_bits1++;
226				switch (hdlc->hdlc_bits1) {
227				case 6:
228					break;
229				case 7:
230					if (hdlc->data_received)
231						/* bad frame */
232						status = -HDLC_FRAMING_ERROR;
233					if (!hdlc->do_adapt56) {
234						if (hdlc->cbin == fast_abort
235						    [hdlc->bit_shift + 1]) {
236							hdlc->state =
237								HDLC_FAST_IDLE;
238							hdlc->bit_shift = 1;
239							break;
240						}
241					} else
242						hdlc->state = HDLC_GET_FLAG_B0;
243					break;
244				default:
245					hdlc->shift_reg >>= 1;
246					hdlc->shift_reg |= 0x80;
247					hdlc->data_bits++;
248					break;
249				}
250			} else {
251				switch (hdlc->hdlc_bits1) {
252				case 5:
253					break;
254				case 6:
255					if (hdlc->data_received)
256						status = check_frame(hdlc);
257					hdlc->crc = 0xffff;
258					hdlc->shift_reg = 0;
259					hdlc->data_bits = 0;
260					if (!hdlc->do_adapt56)
261						handle_fast_flag(hdlc);
262					else {
263						hdlc->state = HDLC_GET_DATA;
264						hdlc->data_received = 0;
265					}
266					break;
267				default:
268					hdlc->shift_reg >>= 1;
269					hdlc->data_bits++;
270					break;
271				}
272				hdlc->hdlc_bits1 = 0;
273			}
274			if (status) {
275				hdlc->dstpos = 0;
276				*count -= slen;
277				hdlc->cbin <<= 1;
278				hdlc->bit_shift--;
279				return status;
280			}
281			if (hdlc->data_bits == 8) {
282				hdlc->data_bits = 0;
283				hdlc->data_received = 1;
284				hdlc->crc = crc_ccitt_byte(hdlc->crc,
285							   hdlc->shift_reg);
286
287				/* good byte received */
288				if (hdlc->dstpos < dsize)
289					dst[hdlc->dstpos++] = hdlc->shift_reg;
290				else {
291					/* frame too long */
292					status = -HDLC_LENGTH_ERROR;
293					hdlc->dstpos = 0;
294				}
295			}
296			hdlc->cbin <<= 1;
297			hdlc->bit_shift--;
298			break;
299		case HDLC_FAST_FLAG:
300			if (hdlc->cbin == hdlc->ffvalue) {
301				hdlc->bit_shift = 0;
302				break;
303			} else {
304				if (hdlc->cbin == 0xff) {
305					hdlc->state = HDLC_FAST_IDLE;
306					hdlc->bit_shift = 0;
307				} else if (hdlc->ffbit_shift == 8) {
308					hdlc->state = HDLC_GETFLAG_B7;
309					break;
310				} else
311					handle_abort(hdlc);
312			}
313			break;
314		default:
315			break;
316		}
317	}
318	*count -= slen;
319	return 0;
320}
321EXPORT_SYMBOL(isdnhdlc_decode);
322/*
323  isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
324
325  The bit stream starts with a beginning flag (01111110). After
326  that each byte is added to the bit stream with bit stuffing added
327  (0 after 5 1's).
328  When the last byte has been removed from the source buffer, the
329  CRC (2 bytes is added) and the frame terminates with the ending flag.
330  For the dchannel, the idle character (all 1's) is also added at the end.
331  If this function is called with empty source buffer (slen=0), flags or
332  idle character will be generated.
333
334  src - source buffer
335  slen - source buffer length
336  count - number of bytes removed (encoded) from source buffer
337  dst _ destination buffer
338  dsize - destination buffer size
339  returns - number of encoded bytes in the destination buffer
340*/
341int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
342		    int *count, u8 *dst, int dsize)
343{
344	static const unsigned char xfast_flag_value[] = {
345		0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
346	};
347
348	int len = 0;
349
350	*count = slen;
351
352	/* special handling for one byte frames */
353	if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
354		hdlc->state = HDLC_SENDFLAG_ONE;
355	while (dsize > 0) {
356		if (hdlc->bit_shift == 0) {
357			if (slen && !hdlc->do_closing) {
358				hdlc->shift_reg = *src++;
359				slen--;
360				if (slen == 0)
361					/* closing sequence, CRC + flag(s) */
362					hdlc->do_closing = 1;
363				hdlc->bit_shift = 8;
364			} else {
365				if (hdlc->state == HDLC_SEND_DATA) {
366					if (hdlc->data_received) {
367						hdlc->state = HDLC_SEND_CRC1;
368						hdlc->crc ^= 0xffff;
369						hdlc->bit_shift = 8;
370						hdlc->shift_reg =
371							hdlc->crc & 0xff;
372					} else if (!hdlc->do_adapt56)
373						hdlc->state =
374							HDLC_SEND_FAST_FLAG;
375					else
376						hdlc->state =
377							HDLC_SENDFLAG_B0;
378				}
379
380			}
381		}
382
383		switch (hdlc->state) {
384		case STOPPED:
385			while (dsize--)
386				*dst++ = 0xff;
387			return dsize;
388		case HDLC_SEND_FAST_FLAG:
389			hdlc->do_closing = 0;
390			if (slen == 0) {
391				/* the code is for bitreverse streams */
392				if (hdlc->do_bitreverse == 0)
393					*dst++ = bitrev8(hdlc->ffvalue);
394				else
395					*dst++ = hdlc->ffvalue;
396				len++;
397				dsize--;
398				break;
399			}
400			fallthrough;
401		case HDLC_SENDFLAG_ONE:
402			if (hdlc->bit_shift == 8) {
403				hdlc->cbin = hdlc->ffvalue >>
404					(8 - hdlc->data_bits);
405				hdlc->state = HDLC_SEND_DATA;
406				hdlc->crc = 0xffff;
407				hdlc->hdlc_bits1 = 0;
408				hdlc->data_received = 1;
409			}
410			break;
411		case HDLC_SENDFLAG_B0:
412			hdlc->do_closing = 0;
413			hdlc->cbin <<= 1;
414			hdlc->data_bits++;
415			hdlc->hdlc_bits1 = 0;
416			hdlc->state = HDLC_SENDFLAG_B1A6;
417			break;
418		case HDLC_SENDFLAG_B1A6:
419			hdlc->cbin <<= 1;
420			hdlc->data_bits++;
421			hdlc->cbin++;
422			if (++hdlc->hdlc_bits1 == 6)
423				hdlc->state = HDLC_SENDFLAG_B7;
424			break;
425		case HDLC_SENDFLAG_B7:
426			hdlc->cbin <<= 1;
427			hdlc->data_bits++;
428			if (slen == 0) {
429				hdlc->state = HDLC_SENDFLAG_B0;
430				break;
431			}
432			if (hdlc->bit_shift == 8) {
433				hdlc->state = HDLC_SEND_DATA;
434				hdlc->crc = 0xffff;
435				hdlc->hdlc_bits1 = 0;
436				hdlc->data_received = 1;
437			}
438			break;
439		case HDLC_SEND_FIRST_FLAG:
440			hdlc->data_received = 1;
441			if (hdlc->data_bits == 8) {
442				hdlc->state = HDLC_SEND_DATA;
443				hdlc->crc = 0xffff;
444				hdlc->hdlc_bits1 = 0;
445				break;
446			}
447			hdlc->cbin <<= 1;
448			hdlc->data_bits++;
449			if (hdlc->shift_reg & 0x01)
450				hdlc->cbin++;
451			hdlc->shift_reg >>= 1;
452			hdlc->bit_shift--;
453			if (hdlc->bit_shift == 0) {
454				hdlc->state = HDLC_SEND_DATA;
455				hdlc->crc = 0xffff;
456				hdlc->hdlc_bits1 = 0;
457			}
458			break;
459		case HDLC_SEND_DATA:
460			hdlc->cbin <<= 1;
461			hdlc->data_bits++;
462			if (hdlc->hdlc_bits1 == 5) {
463				hdlc->hdlc_bits1 = 0;
464				break;
465			}
466			if (hdlc->bit_shift == 8)
467				hdlc->crc = crc_ccitt_byte(hdlc->crc,
468							   hdlc->shift_reg);
469			if (hdlc->shift_reg & 0x01) {
470				hdlc->hdlc_bits1++;
471				hdlc->cbin++;
472				hdlc->shift_reg >>= 1;
473				hdlc->bit_shift--;
474			} else {
475				hdlc->hdlc_bits1 = 0;
476				hdlc->shift_reg >>= 1;
477				hdlc->bit_shift--;
478			}
479			break;
480		case HDLC_SEND_CRC1:
481			hdlc->cbin <<= 1;
482			hdlc->data_bits++;
483			if (hdlc->hdlc_bits1 == 5) {
484				hdlc->hdlc_bits1 = 0;
485				break;
486			}
487			if (hdlc->shift_reg & 0x01) {
488				hdlc->hdlc_bits1++;
489				hdlc->cbin++;
490				hdlc->shift_reg >>= 1;
491				hdlc->bit_shift--;
492			} else {
493				hdlc->hdlc_bits1 = 0;
494				hdlc->shift_reg >>= 1;
495				hdlc->bit_shift--;
496			}
497			if (hdlc->bit_shift == 0) {
498				hdlc->shift_reg = (hdlc->crc >> 8);
499				hdlc->state = HDLC_SEND_CRC2;
500				hdlc->bit_shift = 8;
501			}
502			break;
503		case HDLC_SEND_CRC2:
504			hdlc->cbin <<= 1;
505			hdlc->data_bits++;
506			if (hdlc->hdlc_bits1 == 5) {
507				hdlc->hdlc_bits1 = 0;
508				break;
509			}
510			if (hdlc->shift_reg & 0x01) {
511				hdlc->hdlc_bits1++;
512				hdlc->cbin++;
513				hdlc->shift_reg >>= 1;
514				hdlc->bit_shift--;
515			} else {
516				hdlc->hdlc_bits1 = 0;
517				hdlc->shift_reg >>= 1;
518				hdlc->bit_shift--;
519			}
520			if (hdlc->bit_shift == 0) {
521				hdlc->shift_reg = 0x7e;
522				hdlc->state = HDLC_SEND_CLOSING_FLAG;
523				hdlc->bit_shift = 8;
524			}
525			break;
526		case HDLC_SEND_CLOSING_FLAG:
527			hdlc->cbin <<= 1;
528			hdlc->data_bits++;
529			if (hdlc->hdlc_bits1 == 5) {
530				hdlc->hdlc_bits1 = 0;
531				break;
532			}
533			if (hdlc->shift_reg & 0x01)
534				hdlc->cbin++;
535			hdlc->shift_reg >>= 1;
536			hdlc->bit_shift--;
537			if (hdlc->bit_shift == 0) {
538				hdlc->ffvalue =
539					xfast_flag_value[hdlc->data_bits];
540				if (hdlc->dchannel) {
541					hdlc->ffvalue = 0x7e;
542					hdlc->state = HDLC_SEND_IDLE1;
543					hdlc->bit_shift = 8-hdlc->data_bits;
544					if (hdlc->bit_shift == 0)
545						hdlc->state =
546							HDLC_SEND_FAST_IDLE;
547				} else {
548					if (!hdlc->do_adapt56) {
549						hdlc->state =
550							HDLC_SEND_FAST_FLAG;
551						hdlc->data_received = 0;
552					} else {
553						hdlc->state = HDLC_SENDFLAG_B0;
554						hdlc->data_received = 0;
555					}
556					/* Finished this frame, send flags */
557					if (dsize > 1)
558						dsize = 1;
559				}
560			}
561			break;
562		case HDLC_SEND_IDLE1:
563			hdlc->do_closing = 0;
564			hdlc->cbin <<= 1;
565			hdlc->cbin++;
566			hdlc->data_bits++;
567			hdlc->bit_shift--;
568			if (hdlc->bit_shift == 0) {
569				hdlc->state = HDLC_SEND_FAST_IDLE;
570				hdlc->bit_shift = 0;
571			}
572			break;
573		case HDLC_SEND_FAST_IDLE:
574			hdlc->do_closing = 0;
575			hdlc->cbin = 0xff;
576			hdlc->data_bits = 8;
577			if (hdlc->bit_shift == 8) {
578				hdlc->cbin = 0x7e;
579				hdlc->state = HDLC_SEND_FIRST_FLAG;
580			} else {
581				/* the code is for bitreverse streams */
582				if (hdlc->do_bitreverse == 0)
583					*dst++ = bitrev8(hdlc->cbin);
584				else
585					*dst++ = hdlc->cbin;
586				hdlc->bit_shift = 0;
587				hdlc->data_bits = 0;
588				len++;
589				dsize = 0;
590			}
591			break;
592		default:
593			break;
594		}
595		if (hdlc->do_adapt56) {
596			if (hdlc->data_bits == 7) {
597				hdlc->cbin <<= 1;
598				hdlc->cbin++;
599				hdlc->data_bits++;
600			}
601		}
602		if (hdlc->data_bits == 8) {
603			/* the code is for bitreverse streams */
604			if (hdlc->do_bitreverse == 0)
605				*dst++ = bitrev8(hdlc->cbin);
606			else
607				*dst++ = hdlc->cbin;
608			hdlc->data_bits = 0;
609			len++;
610			dsize--;
611		}
612	}
613	*count -= slen;
614
615	return len;
616}
617EXPORT_SYMBOL(isdnhdlc_encode);
618