18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C)
68c2ecf20Sopenharmony_ci *	2009	Karsten Keil		<keil@b1-systems.de>
78c2ecf20Sopenharmony_ci *	2002	Wolfgang Mües		<wolfgang@iksw-muees.de>
88c2ecf20Sopenharmony_ci *	2001	Frode Isaksen		<fisaksen@bewan.com>
98c2ecf20Sopenharmony_ci *      2001	Kai Germaschewski	<kai.germaschewski@gmx.de>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/crc-ccitt.h>
158c2ecf20Sopenharmony_ci#include <linux/bitrev.h>
168c2ecf20Sopenharmony_ci#include "isdnhdlc.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------*/
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
218c2ecf20Sopenharmony_ci	      "Frode Isaksen <fisaksen@bewan.com>, "
228c2ecf20Sopenharmony_ci	      "Kai Germaschewski <kai.germaschewski@gmx.de>");
238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------*/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cienum {
298c2ecf20Sopenharmony_ci	HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
308c2ecf20Sopenharmony_ci	HDLC_GET_DATA, HDLC_FAST_FLAG
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cienum {
348c2ecf20Sopenharmony_ci	HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
358c2ecf20Sopenharmony_ci	HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
368c2ecf20Sopenharmony_ci	HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
378c2ecf20Sopenharmony_ci	HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_civoid isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
438c2ecf20Sopenharmony_ci	hdlc->state = HDLC_GET_DATA;
448c2ecf20Sopenharmony_ci	if (features & HDLC_56KBIT)
458c2ecf20Sopenharmony_ci		hdlc->do_adapt56 = 1;
468c2ecf20Sopenharmony_ci	if (features & HDLC_BITREVERSE)
478c2ecf20Sopenharmony_ci		hdlc->do_bitreverse = 1;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_out_init);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_civoid isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
548c2ecf20Sopenharmony_ci	if (features & HDLC_DCHANNEL) {
558c2ecf20Sopenharmony_ci		hdlc->dchannel = 1;
568c2ecf20Sopenharmony_ci		hdlc->state = HDLC_SEND_FIRST_FLAG;
578c2ecf20Sopenharmony_ci	} else {
588c2ecf20Sopenharmony_ci		hdlc->dchannel = 0;
598c2ecf20Sopenharmony_ci		hdlc->state = HDLC_SEND_FAST_FLAG;
608c2ecf20Sopenharmony_ci		hdlc->ffvalue = 0x7e;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci	hdlc->cbin = 0x7e;
638c2ecf20Sopenharmony_ci	if (features & HDLC_56KBIT) {
648c2ecf20Sopenharmony_ci		hdlc->do_adapt56 = 1;
658c2ecf20Sopenharmony_ci		hdlc->state = HDLC_SENDFLAG_B0;
668c2ecf20Sopenharmony_ci	} else
678c2ecf20Sopenharmony_ci		hdlc->data_bits = 8;
688c2ecf20Sopenharmony_ci	if (features & HDLC_BITREVERSE)
698c2ecf20Sopenharmony_ci		hdlc->do_bitreverse = 1;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_rcv_init);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int
748c2ecf20Sopenharmony_cicheck_frame(struct isdnhdlc_vars *hdlc)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	int status;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (hdlc->dstpos < 2)	/* too small - framing error */
798c2ecf20Sopenharmony_ci		status = -HDLC_FRAMING_ERROR;
808c2ecf20Sopenharmony_ci	else if (hdlc->crc != 0xf0b8)	/* crc error */
818c2ecf20Sopenharmony_ci		status = -HDLC_CRC_ERROR;
828c2ecf20Sopenharmony_ci	else {
838c2ecf20Sopenharmony_ci		/* remove CRC */
848c2ecf20Sopenharmony_ci		hdlc->dstpos -= 2;
858c2ecf20Sopenharmony_ci		/* good frame */
868c2ecf20Sopenharmony_ci		status = hdlc->dstpos;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci	return status;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/*
928c2ecf20Sopenharmony_ci  isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci  The source buffer is scanned for valid HDLC frames looking for
958c2ecf20Sopenharmony_ci  flags (01111110) to indicate the start of a frame. If the start of
968c2ecf20Sopenharmony_ci  the frame is found, the bit stuffing is removed (0 after 5 1's).
978c2ecf20Sopenharmony_ci  When a new flag is found, the complete frame has been received
988c2ecf20Sopenharmony_ci  and the CRC is checked.
998c2ecf20Sopenharmony_ci  If a valid frame is found, the function returns the frame length
1008c2ecf20Sopenharmony_ci  excluding the CRC with the bit HDLC_END_OF_FRAME set.
1018c2ecf20Sopenharmony_ci  If the beginning of a valid frame is found, the function returns
1028c2ecf20Sopenharmony_ci  the length.
1038c2ecf20Sopenharmony_ci  If a framing error is found (too many 1s and not a flag) the function
1048c2ecf20Sopenharmony_ci  returns the length with the bit HDLC_FRAMING_ERROR set.
1058c2ecf20Sopenharmony_ci  If a CRC error is found the function returns the length with the
1068c2ecf20Sopenharmony_ci  bit HDLC_CRC_ERROR set.
1078c2ecf20Sopenharmony_ci  If the frame length exceeds the destination buffer size, the function
1088c2ecf20Sopenharmony_ci  returns the length with the bit HDLC_LENGTH_ERROR set.
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci  src - source buffer
1118c2ecf20Sopenharmony_ci  slen - source buffer length
1128c2ecf20Sopenharmony_ci  count - number of bytes removed (decoded) from the source buffer
1138c2ecf20Sopenharmony_ci  dst _ destination buffer
1148c2ecf20Sopenharmony_ci  dsize - destination buffer size
1158c2ecf20Sopenharmony_ci  returns - number of decoded bytes in the destination buffer and status
1168c2ecf20Sopenharmony_ci  flag.
1178c2ecf20Sopenharmony_ci*/
1188c2ecf20Sopenharmony_ciint isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
1198c2ecf20Sopenharmony_ci		    int *count, u8 *dst, int dsize)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	int status = 0;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	static const unsigned char fast_flag[] = {
1248c2ecf20Sopenharmony_ci		0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
1258c2ecf20Sopenharmony_ci	};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	static const unsigned char fast_flag_value[] = {
1288c2ecf20Sopenharmony_ci		0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
1298c2ecf20Sopenharmony_ci	};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	static const unsigned char fast_abort[] = {
1328c2ecf20Sopenharmony_ci		0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
1338c2ecf20Sopenharmony_ci	};
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#define handle_fast_flag(h)						\
1368c2ecf20Sopenharmony_ci	do {								\
1378c2ecf20Sopenharmony_ci		if (h->cbin == fast_flag[h->bit_shift]) {		\
1388c2ecf20Sopenharmony_ci			h->ffvalue = fast_flag_value[h->bit_shift];	\
1398c2ecf20Sopenharmony_ci			h->state = HDLC_FAST_FLAG;			\
1408c2ecf20Sopenharmony_ci			h->ffbit_shift = h->bit_shift;			\
1418c2ecf20Sopenharmony_ci			h->bit_shift = 1;				\
1428c2ecf20Sopenharmony_ci		} else {						\
1438c2ecf20Sopenharmony_ci			h->state = HDLC_GET_DATA;			\
1448c2ecf20Sopenharmony_ci			h->data_received = 0;				\
1458c2ecf20Sopenharmony_ci		}							\
1468c2ecf20Sopenharmony_ci	} while (0)
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#define handle_abort(h)						\
1498c2ecf20Sopenharmony_ci	do {							\
1508c2ecf20Sopenharmony_ci		h->shift_reg = fast_abort[h->ffbit_shift - 1];	\
1518c2ecf20Sopenharmony_ci		h->hdlc_bits1 = h->ffbit_shift - 2;		\
1528c2ecf20Sopenharmony_ci		if (h->hdlc_bits1 < 0)				\
1538c2ecf20Sopenharmony_ci			h->hdlc_bits1 = 0;			\
1548c2ecf20Sopenharmony_ci		h->data_bits = h->ffbit_shift - 1;		\
1558c2ecf20Sopenharmony_ci		h->state = HDLC_GET_DATA;			\
1568c2ecf20Sopenharmony_ci		h->data_received = 0;				\
1578c2ecf20Sopenharmony_ci	} while (0)
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	*count = slen;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	while (slen > 0) {
1628c2ecf20Sopenharmony_ci		if (hdlc->bit_shift == 0) {
1638c2ecf20Sopenharmony_ci			/* the code is for bitreverse streams */
1648c2ecf20Sopenharmony_ci			if (hdlc->do_bitreverse == 0)
1658c2ecf20Sopenharmony_ci				hdlc->cbin = bitrev8(*src++);
1668c2ecf20Sopenharmony_ci			else
1678c2ecf20Sopenharmony_ci				hdlc->cbin = *src++;
1688c2ecf20Sopenharmony_ci			slen--;
1698c2ecf20Sopenharmony_ci			hdlc->bit_shift = 8;
1708c2ecf20Sopenharmony_ci			if (hdlc->do_adapt56)
1718c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		switch (hdlc->state) {
1758c2ecf20Sopenharmony_ci		case STOPPED:
1768c2ecf20Sopenharmony_ci			return 0;
1778c2ecf20Sopenharmony_ci		case HDLC_FAST_IDLE:
1788c2ecf20Sopenharmony_ci			if (hdlc->cbin == 0xff) {
1798c2ecf20Sopenharmony_ci				hdlc->bit_shift = 0;
1808c2ecf20Sopenharmony_ci				break;
1818c2ecf20Sopenharmony_ci			}
1828c2ecf20Sopenharmony_ci			hdlc->state = HDLC_GET_FLAG_B0;
1838c2ecf20Sopenharmony_ci			hdlc->hdlc_bits1 = 0;
1848c2ecf20Sopenharmony_ci			hdlc->bit_shift = 8;
1858c2ecf20Sopenharmony_ci			break;
1868c2ecf20Sopenharmony_ci		case HDLC_GET_FLAG_B0:
1878c2ecf20Sopenharmony_ci			if (!(hdlc->cbin & 0x80)) {
1888c2ecf20Sopenharmony_ci				hdlc->state = HDLC_GETFLAG_B1A6;
1898c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
1908c2ecf20Sopenharmony_ci			} else {
1918c2ecf20Sopenharmony_ci				if ((!hdlc->do_adapt56) &&
1928c2ecf20Sopenharmony_ci				    (++hdlc->hdlc_bits1 >= 8) &&
1938c2ecf20Sopenharmony_ci				    (hdlc->bit_shift == 1))
1948c2ecf20Sopenharmony_ci					hdlc->state = HDLC_FAST_IDLE;
1958c2ecf20Sopenharmony_ci			}
1968c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
1978c2ecf20Sopenharmony_ci			hdlc->bit_shift--;
1988c2ecf20Sopenharmony_ci			break;
1998c2ecf20Sopenharmony_ci		case HDLC_GETFLAG_B1A6:
2008c2ecf20Sopenharmony_ci			if (hdlc->cbin & 0x80) {
2018c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1++;
2028c2ecf20Sopenharmony_ci				if (hdlc->hdlc_bits1 == 6)
2038c2ecf20Sopenharmony_ci					hdlc->state = HDLC_GETFLAG_B7;
2048c2ecf20Sopenharmony_ci			} else
2058c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
2068c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
2078c2ecf20Sopenharmony_ci			hdlc->bit_shift--;
2088c2ecf20Sopenharmony_ci			break;
2098c2ecf20Sopenharmony_ci		case HDLC_GETFLAG_B7:
2108c2ecf20Sopenharmony_ci			if (hdlc->cbin & 0x80) {
2118c2ecf20Sopenharmony_ci				hdlc->state = HDLC_GET_FLAG_B0;
2128c2ecf20Sopenharmony_ci			} else {
2138c2ecf20Sopenharmony_ci				hdlc->state = HDLC_GET_DATA;
2148c2ecf20Sopenharmony_ci				hdlc->crc = 0xffff;
2158c2ecf20Sopenharmony_ci				hdlc->shift_reg = 0;
2168c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
2178c2ecf20Sopenharmony_ci				hdlc->data_bits = 0;
2188c2ecf20Sopenharmony_ci				hdlc->data_received = 0;
2198c2ecf20Sopenharmony_ci			}
2208c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
2218c2ecf20Sopenharmony_ci			hdlc->bit_shift--;
2228c2ecf20Sopenharmony_ci			break;
2238c2ecf20Sopenharmony_ci		case HDLC_GET_DATA:
2248c2ecf20Sopenharmony_ci			if (hdlc->cbin & 0x80) {
2258c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1++;
2268c2ecf20Sopenharmony_ci				switch (hdlc->hdlc_bits1) {
2278c2ecf20Sopenharmony_ci				case 6:
2288c2ecf20Sopenharmony_ci					break;
2298c2ecf20Sopenharmony_ci				case 7:
2308c2ecf20Sopenharmony_ci					if (hdlc->data_received)
2318c2ecf20Sopenharmony_ci						/* bad frame */
2328c2ecf20Sopenharmony_ci						status = -HDLC_FRAMING_ERROR;
2338c2ecf20Sopenharmony_ci					if (!hdlc->do_adapt56) {
2348c2ecf20Sopenharmony_ci						if (hdlc->cbin == fast_abort
2358c2ecf20Sopenharmony_ci						    [hdlc->bit_shift + 1]) {
2368c2ecf20Sopenharmony_ci							hdlc->state =
2378c2ecf20Sopenharmony_ci								HDLC_FAST_IDLE;
2388c2ecf20Sopenharmony_ci							hdlc->bit_shift = 1;
2398c2ecf20Sopenharmony_ci							break;
2408c2ecf20Sopenharmony_ci						}
2418c2ecf20Sopenharmony_ci					} else
2428c2ecf20Sopenharmony_ci						hdlc->state = HDLC_GET_FLAG_B0;
2438c2ecf20Sopenharmony_ci					break;
2448c2ecf20Sopenharmony_ci				default:
2458c2ecf20Sopenharmony_ci					hdlc->shift_reg >>= 1;
2468c2ecf20Sopenharmony_ci					hdlc->shift_reg |= 0x80;
2478c2ecf20Sopenharmony_ci					hdlc->data_bits++;
2488c2ecf20Sopenharmony_ci					break;
2498c2ecf20Sopenharmony_ci				}
2508c2ecf20Sopenharmony_ci			} else {
2518c2ecf20Sopenharmony_ci				switch (hdlc->hdlc_bits1) {
2528c2ecf20Sopenharmony_ci				case 5:
2538c2ecf20Sopenharmony_ci					break;
2548c2ecf20Sopenharmony_ci				case 6:
2558c2ecf20Sopenharmony_ci					if (hdlc->data_received)
2568c2ecf20Sopenharmony_ci						status = check_frame(hdlc);
2578c2ecf20Sopenharmony_ci					hdlc->crc = 0xffff;
2588c2ecf20Sopenharmony_ci					hdlc->shift_reg = 0;
2598c2ecf20Sopenharmony_ci					hdlc->data_bits = 0;
2608c2ecf20Sopenharmony_ci					if (!hdlc->do_adapt56)
2618c2ecf20Sopenharmony_ci						handle_fast_flag(hdlc);
2628c2ecf20Sopenharmony_ci					else {
2638c2ecf20Sopenharmony_ci						hdlc->state = HDLC_GET_DATA;
2648c2ecf20Sopenharmony_ci						hdlc->data_received = 0;
2658c2ecf20Sopenharmony_ci					}
2668c2ecf20Sopenharmony_ci					break;
2678c2ecf20Sopenharmony_ci				default:
2688c2ecf20Sopenharmony_ci					hdlc->shift_reg >>= 1;
2698c2ecf20Sopenharmony_ci					hdlc->data_bits++;
2708c2ecf20Sopenharmony_ci					break;
2718c2ecf20Sopenharmony_ci				}
2728c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
2738c2ecf20Sopenharmony_ci			}
2748c2ecf20Sopenharmony_ci			if (status) {
2758c2ecf20Sopenharmony_ci				hdlc->dstpos = 0;
2768c2ecf20Sopenharmony_ci				*count -= slen;
2778c2ecf20Sopenharmony_ci				hdlc->cbin <<= 1;
2788c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
2798c2ecf20Sopenharmony_ci				return status;
2808c2ecf20Sopenharmony_ci			}
2818c2ecf20Sopenharmony_ci			if (hdlc->data_bits == 8) {
2828c2ecf20Sopenharmony_ci				hdlc->data_bits = 0;
2838c2ecf20Sopenharmony_ci				hdlc->data_received = 1;
2848c2ecf20Sopenharmony_ci				hdlc->crc = crc_ccitt_byte(hdlc->crc,
2858c2ecf20Sopenharmony_ci							   hdlc->shift_reg);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci				/* good byte received */
2888c2ecf20Sopenharmony_ci				if (hdlc->dstpos < dsize)
2898c2ecf20Sopenharmony_ci					dst[hdlc->dstpos++] = hdlc->shift_reg;
2908c2ecf20Sopenharmony_ci				else {
2918c2ecf20Sopenharmony_ci					/* frame too long */
2928c2ecf20Sopenharmony_ci					status = -HDLC_LENGTH_ERROR;
2938c2ecf20Sopenharmony_ci					hdlc->dstpos = 0;
2948c2ecf20Sopenharmony_ci				}
2958c2ecf20Sopenharmony_ci			}
2968c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
2978c2ecf20Sopenharmony_ci			hdlc->bit_shift--;
2988c2ecf20Sopenharmony_ci			break;
2998c2ecf20Sopenharmony_ci		case HDLC_FAST_FLAG:
3008c2ecf20Sopenharmony_ci			if (hdlc->cbin == hdlc->ffvalue) {
3018c2ecf20Sopenharmony_ci				hdlc->bit_shift = 0;
3028c2ecf20Sopenharmony_ci				break;
3038c2ecf20Sopenharmony_ci			} else {
3048c2ecf20Sopenharmony_ci				if (hdlc->cbin == 0xff) {
3058c2ecf20Sopenharmony_ci					hdlc->state = HDLC_FAST_IDLE;
3068c2ecf20Sopenharmony_ci					hdlc->bit_shift = 0;
3078c2ecf20Sopenharmony_ci				} else if (hdlc->ffbit_shift == 8) {
3088c2ecf20Sopenharmony_ci					hdlc->state = HDLC_GETFLAG_B7;
3098c2ecf20Sopenharmony_ci					break;
3108c2ecf20Sopenharmony_ci				} else
3118c2ecf20Sopenharmony_ci					handle_abort(hdlc);
3128c2ecf20Sopenharmony_ci			}
3138c2ecf20Sopenharmony_ci			break;
3148c2ecf20Sopenharmony_ci		default:
3158c2ecf20Sopenharmony_ci			break;
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci	*count -= slen;
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_decode);
3228c2ecf20Sopenharmony_ci/*
3238c2ecf20Sopenharmony_ci  isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci  The bit stream starts with a beginning flag (01111110). After
3268c2ecf20Sopenharmony_ci  that each byte is added to the bit stream with bit stuffing added
3278c2ecf20Sopenharmony_ci  (0 after 5 1's).
3288c2ecf20Sopenharmony_ci  When the last byte has been removed from the source buffer, the
3298c2ecf20Sopenharmony_ci  CRC (2 bytes is added) and the frame terminates with the ending flag.
3308c2ecf20Sopenharmony_ci  For the dchannel, the idle character (all 1's) is also added at the end.
3318c2ecf20Sopenharmony_ci  If this function is called with empty source buffer (slen=0), flags or
3328c2ecf20Sopenharmony_ci  idle character will be generated.
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci  src - source buffer
3358c2ecf20Sopenharmony_ci  slen - source buffer length
3368c2ecf20Sopenharmony_ci  count - number of bytes removed (encoded) from source buffer
3378c2ecf20Sopenharmony_ci  dst _ destination buffer
3388c2ecf20Sopenharmony_ci  dsize - destination buffer size
3398c2ecf20Sopenharmony_ci  returns - number of encoded bytes in the destination buffer
3408c2ecf20Sopenharmony_ci*/
3418c2ecf20Sopenharmony_ciint isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
3428c2ecf20Sopenharmony_ci		    int *count, u8 *dst, int dsize)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	static const unsigned char xfast_flag_value[] = {
3458c2ecf20Sopenharmony_ci		0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
3468c2ecf20Sopenharmony_ci	};
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	int len = 0;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	*count = slen;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* special handling for one byte frames */
3538c2ecf20Sopenharmony_ci	if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
3548c2ecf20Sopenharmony_ci		hdlc->state = HDLC_SENDFLAG_ONE;
3558c2ecf20Sopenharmony_ci	while (dsize > 0) {
3568c2ecf20Sopenharmony_ci		if (hdlc->bit_shift == 0) {
3578c2ecf20Sopenharmony_ci			if (slen && !hdlc->do_closing) {
3588c2ecf20Sopenharmony_ci				hdlc->shift_reg = *src++;
3598c2ecf20Sopenharmony_ci				slen--;
3608c2ecf20Sopenharmony_ci				if (slen == 0)
3618c2ecf20Sopenharmony_ci					/* closing sequence, CRC + flag(s) */
3628c2ecf20Sopenharmony_ci					hdlc->do_closing = 1;
3638c2ecf20Sopenharmony_ci				hdlc->bit_shift = 8;
3648c2ecf20Sopenharmony_ci			} else {
3658c2ecf20Sopenharmony_ci				if (hdlc->state == HDLC_SEND_DATA) {
3668c2ecf20Sopenharmony_ci					if (hdlc->data_received) {
3678c2ecf20Sopenharmony_ci						hdlc->state = HDLC_SEND_CRC1;
3688c2ecf20Sopenharmony_ci						hdlc->crc ^= 0xffff;
3698c2ecf20Sopenharmony_ci						hdlc->bit_shift = 8;
3708c2ecf20Sopenharmony_ci						hdlc->shift_reg =
3718c2ecf20Sopenharmony_ci							hdlc->crc & 0xff;
3728c2ecf20Sopenharmony_ci					} else if (!hdlc->do_adapt56)
3738c2ecf20Sopenharmony_ci						hdlc->state =
3748c2ecf20Sopenharmony_ci							HDLC_SEND_FAST_FLAG;
3758c2ecf20Sopenharmony_ci					else
3768c2ecf20Sopenharmony_ci						hdlc->state =
3778c2ecf20Sopenharmony_ci							HDLC_SENDFLAG_B0;
3788c2ecf20Sopenharmony_ci				}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci			}
3818c2ecf20Sopenharmony_ci		}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		switch (hdlc->state) {
3848c2ecf20Sopenharmony_ci		case STOPPED:
3858c2ecf20Sopenharmony_ci			while (dsize--)
3868c2ecf20Sopenharmony_ci				*dst++ = 0xff;
3878c2ecf20Sopenharmony_ci			return dsize;
3888c2ecf20Sopenharmony_ci		case HDLC_SEND_FAST_FLAG:
3898c2ecf20Sopenharmony_ci			hdlc->do_closing = 0;
3908c2ecf20Sopenharmony_ci			if (slen == 0) {
3918c2ecf20Sopenharmony_ci				/* the code is for bitreverse streams */
3928c2ecf20Sopenharmony_ci				if (hdlc->do_bitreverse == 0)
3938c2ecf20Sopenharmony_ci					*dst++ = bitrev8(hdlc->ffvalue);
3948c2ecf20Sopenharmony_ci				else
3958c2ecf20Sopenharmony_ci					*dst++ = hdlc->ffvalue;
3968c2ecf20Sopenharmony_ci				len++;
3978c2ecf20Sopenharmony_ci				dsize--;
3988c2ecf20Sopenharmony_ci				break;
3998c2ecf20Sopenharmony_ci			}
4008c2ecf20Sopenharmony_ci			fallthrough;
4018c2ecf20Sopenharmony_ci		case HDLC_SENDFLAG_ONE:
4028c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 8) {
4038c2ecf20Sopenharmony_ci				hdlc->cbin = hdlc->ffvalue >>
4048c2ecf20Sopenharmony_ci					(8 - hdlc->data_bits);
4058c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_DATA;
4068c2ecf20Sopenharmony_ci				hdlc->crc = 0xffff;
4078c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4088c2ecf20Sopenharmony_ci				hdlc->data_received = 1;
4098c2ecf20Sopenharmony_ci			}
4108c2ecf20Sopenharmony_ci			break;
4118c2ecf20Sopenharmony_ci		case HDLC_SENDFLAG_B0:
4128c2ecf20Sopenharmony_ci			hdlc->do_closing = 0;
4138c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
4148c2ecf20Sopenharmony_ci			hdlc->data_bits++;
4158c2ecf20Sopenharmony_ci			hdlc->hdlc_bits1 = 0;
4168c2ecf20Sopenharmony_ci			hdlc->state = HDLC_SENDFLAG_B1A6;
4178c2ecf20Sopenharmony_ci			break;
4188c2ecf20Sopenharmony_ci		case HDLC_SENDFLAG_B1A6:
4198c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
4208c2ecf20Sopenharmony_ci			hdlc->data_bits++;
4218c2ecf20Sopenharmony_ci			hdlc->cbin++;
4228c2ecf20Sopenharmony_ci			if (++hdlc->hdlc_bits1 == 6)
4238c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SENDFLAG_B7;
4248c2ecf20Sopenharmony_ci			break;
4258c2ecf20Sopenharmony_ci		case HDLC_SENDFLAG_B7:
4268c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
4278c2ecf20Sopenharmony_ci			hdlc->data_bits++;
4288c2ecf20Sopenharmony_ci			if (slen == 0) {
4298c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SENDFLAG_B0;
4308c2ecf20Sopenharmony_ci				break;
4318c2ecf20Sopenharmony_ci			}
4328c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 8) {
4338c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_DATA;
4348c2ecf20Sopenharmony_ci				hdlc->crc = 0xffff;
4358c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4368c2ecf20Sopenharmony_ci				hdlc->data_received = 1;
4378c2ecf20Sopenharmony_ci			}
4388c2ecf20Sopenharmony_ci			break;
4398c2ecf20Sopenharmony_ci		case HDLC_SEND_FIRST_FLAG:
4408c2ecf20Sopenharmony_ci			hdlc->data_received = 1;
4418c2ecf20Sopenharmony_ci			if (hdlc->data_bits == 8) {
4428c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_DATA;
4438c2ecf20Sopenharmony_ci				hdlc->crc = 0xffff;
4448c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4458c2ecf20Sopenharmony_ci				break;
4468c2ecf20Sopenharmony_ci			}
4478c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
4488c2ecf20Sopenharmony_ci			hdlc->data_bits++;
4498c2ecf20Sopenharmony_ci			if (hdlc->shift_reg & 0x01)
4508c2ecf20Sopenharmony_ci				hdlc->cbin++;
4518c2ecf20Sopenharmony_ci			hdlc->shift_reg >>= 1;
4528c2ecf20Sopenharmony_ci			hdlc->bit_shift--;
4538c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 0) {
4548c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_DATA;
4558c2ecf20Sopenharmony_ci				hdlc->crc = 0xffff;
4568c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4578c2ecf20Sopenharmony_ci			}
4588c2ecf20Sopenharmony_ci			break;
4598c2ecf20Sopenharmony_ci		case HDLC_SEND_DATA:
4608c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
4618c2ecf20Sopenharmony_ci			hdlc->data_bits++;
4628c2ecf20Sopenharmony_ci			if (hdlc->hdlc_bits1 == 5) {
4638c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4648c2ecf20Sopenharmony_ci				break;
4658c2ecf20Sopenharmony_ci			}
4668c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 8)
4678c2ecf20Sopenharmony_ci				hdlc->crc = crc_ccitt_byte(hdlc->crc,
4688c2ecf20Sopenharmony_ci							   hdlc->shift_reg);
4698c2ecf20Sopenharmony_ci			if (hdlc->shift_reg & 0x01) {
4708c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1++;
4718c2ecf20Sopenharmony_ci				hdlc->cbin++;
4728c2ecf20Sopenharmony_ci				hdlc->shift_reg >>= 1;
4738c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
4748c2ecf20Sopenharmony_ci			} else {
4758c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4768c2ecf20Sopenharmony_ci				hdlc->shift_reg >>= 1;
4778c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
4788c2ecf20Sopenharmony_ci			}
4798c2ecf20Sopenharmony_ci			break;
4808c2ecf20Sopenharmony_ci		case HDLC_SEND_CRC1:
4818c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
4828c2ecf20Sopenharmony_ci			hdlc->data_bits++;
4838c2ecf20Sopenharmony_ci			if (hdlc->hdlc_bits1 == 5) {
4848c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4858c2ecf20Sopenharmony_ci				break;
4868c2ecf20Sopenharmony_ci			}
4878c2ecf20Sopenharmony_ci			if (hdlc->shift_reg & 0x01) {
4888c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1++;
4898c2ecf20Sopenharmony_ci				hdlc->cbin++;
4908c2ecf20Sopenharmony_ci				hdlc->shift_reg >>= 1;
4918c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
4928c2ecf20Sopenharmony_ci			} else {
4938c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
4948c2ecf20Sopenharmony_ci				hdlc->shift_reg >>= 1;
4958c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
4968c2ecf20Sopenharmony_ci			}
4978c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 0) {
4988c2ecf20Sopenharmony_ci				hdlc->shift_reg = (hdlc->crc >> 8);
4998c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_CRC2;
5008c2ecf20Sopenharmony_ci				hdlc->bit_shift = 8;
5018c2ecf20Sopenharmony_ci			}
5028c2ecf20Sopenharmony_ci			break;
5038c2ecf20Sopenharmony_ci		case HDLC_SEND_CRC2:
5048c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
5058c2ecf20Sopenharmony_ci			hdlc->data_bits++;
5068c2ecf20Sopenharmony_ci			if (hdlc->hdlc_bits1 == 5) {
5078c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
5088c2ecf20Sopenharmony_ci				break;
5098c2ecf20Sopenharmony_ci			}
5108c2ecf20Sopenharmony_ci			if (hdlc->shift_reg & 0x01) {
5118c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1++;
5128c2ecf20Sopenharmony_ci				hdlc->cbin++;
5138c2ecf20Sopenharmony_ci				hdlc->shift_reg >>= 1;
5148c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
5158c2ecf20Sopenharmony_ci			} else {
5168c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
5178c2ecf20Sopenharmony_ci				hdlc->shift_reg >>= 1;
5188c2ecf20Sopenharmony_ci				hdlc->bit_shift--;
5198c2ecf20Sopenharmony_ci			}
5208c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 0) {
5218c2ecf20Sopenharmony_ci				hdlc->shift_reg = 0x7e;
5228c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_CLOSING_FLAG;
5238c2ecf20Sopenharmony_ci				hdlc->bit_shift = 8;
5248c2ecf20Sopenharmony_ci			}
5258c2ecf20Sopenharmony_ci			break;
5268c2ecf20Sopenharmony_ci		case HDLC_SEND_CLOSING_FLAG:
5278c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
5288c2ecf20Sopenharmony_ci			hdlc->data_bits++;
5298c2ecf20Sopenharmony_ci			if (hdlc->hdlc_bits1 == 5) {
5308c2ecf20Sopenharmony_ci				hdlc->hdlc_bits1 = 0;
5318c2ecf20Sopenharmony_ci				break;
5328c2ecf20Sopenharmony_ci			}
5338c2ecf20Sopenharmony_ci			if (hdlc->shift_reg & 0x01)
5348c2ecf20Sopenharmony_ci				hdlc->cbin++;
5358c2ecf20Sopenharmony_ci			hdlc->shift_reg >>= 1;
5368c2ecf20Sopenharmony_ci			hdlc->bit_shift--;
5378c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 0) {
5388c2ecf20Sopenharmony_ci				hdlc->ffvalue =
5398c2ecf20Sopenharmony_ci					xfast_flag_value[hdlc->data_bits];
5408c2ecf20Sopenharmony_ci				if (hdlc->dchannel) {
5418c2ecf20Sopenharmony_ci					hdlc->ffvalue = 0x7e;
5428c2ecf20Sopenharmony_ci					hdlc->state = HDLC_SEND_IDLE1;
5438c2ecf20Sopenharmony_ci					hdlc->bit_shift = 8-hdlc->data_bits;
5448c2ecf20Sopenharmony_ci					if (hdlc->bit_shift == 0)
5458c2ecf20Sopenharmony_ci						hdlc->state =
5468c2ecf20Sopenharmony_ci							HDLC_SEND_FAST_IDLE;
5478c2ecf20Sopenharmony_ci				} else {
5488c2ecf20Sopenharmony_ci					if (!hdlc->do_adapt56) {
5498c2ecf20Sopenharmony_ci						hdlc->state =
5508c2ecf20Sopenharmony_ci							HDLC_SEND_FAST_FLAG;
5518c2ecf20Sopenharmony_ci						hdlc->data_received = 0;
5528c2ecf20Sopenharmony_ci					} else {
5538c2ecf20Sopenharmony_ci						hdlc->state = HDLC_SENDFLAG_B0;
5548c2ecf20Sopenharmony_ci						hdlc->data_received = 0;
5558c2ecf20Sopenharmony_ci					}
5568c2ecf20Sopenharmony_ci					/* Finished this frame, send flags */
5578c2ecf20Sopenharmony_ci					if (dsize > 1)
5588c2ecf20Sopenharmony_ci						dsize = 1;
5598c2ecf20Sopenharmony_ci				}
5608c2ecf20Sopenharmony_ci			}
5618c2ecf20Sopenharmony_ci			break;
5628c2ecf20Sopenharmony_ci		case HDLC_SEND_IDLE1:
5638c2ecf20Sopenharmony_ci			hdlc->do_closing = 0;
5648c2ecf20Sopenharmony_ci			hdlc->cbin <<= 1;
5658c2ecf20Sopenharmony_ci			hdlc->cbin++;
5668c2ecf20Sopenharmony_ci			hdlc->data_bits++;
5678c2ecf20Sopenharmony_ci			hdlc->bit_shift--;
5688c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 0) {
5698c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_FAST_IDLE;
5708c2ecf20Sopenharmony_ci				hdlc->bit_shift = 0;
5718c2ecf20Sopenharmony_ci			}
5728c2ecf20Sopenharmony_ci			break;
5738c2ecf20Sopenharmony_ci		case HDLC_SEND_FAST_IDLE:
5748c2ecf20Sopenharmony_ci			hdlc->do_closing = 0;
5758c2ecf20Sopenharmony_ci			hdlc->cbin = 0xff;
5768c2ecf20Sopenharmony_ci			hdlc->data_bits = 8;
5778c2ecf20Sopenharmony_ci			if (hdlc->bit_shift == 8) {
5788c2ecf20Sopenharmony_ci				hdlc->cbin = 0x7e;
5798c2ecf20Sopenharmony_ci				hdlc->state = HDLC_SEND_FIRST_FLAG;
5808c2ecf20Sopenharmony_ci			} else {
5818c2ecf20Sopenharmony_ci				/* the code is for bitreverse streams */
5828c2ecf20Sopenharmony_ci				if (hdlc->do_bitreverse == 0)
5838c2ecf20Sopenharmony_ci					*dst++ = bitrev8(hdlc->cbin);
5848c2ecf20Sopenharmony_ci				else
5858c2ecf20Sopenharmony_ci					*dst++ = hdlc->cbin;
5868c2ecf20Sopenharmony_ci				hdlc->bit_shift = 0;
5878c2ecf20Sopenharmony_ci				hdlc->data_bits = 0;
5888c2ecf20Sopenharmony_ci				len++;
5898c2ecf20Sopenharmony_ci				dsize = 0;
5908c2ecf20Sopenharmony_ci			}
5918c2ecf20Sopenharmony_ci			break;
5928c2ecf20Sopenharmony_ci		default:
5938c2ecf20Sopenharmony_ci			break;
5948c2ecf20Sopenharmony_ci		}
5958c2ecf20Sopenharmony_ci		if (hdlc->do_adapt56) {
5968c2ecf20Sopenharmony_ci			if (hdlc->data_bits == 7) {
5978c2ecf20Sopenharmony_ci				hdlc->cbin <<= 1;
5988c2ecf20Sopenharmony_ci				hdlc->cbin++;
5998c2ecf20Sopenharmony_ci				hdlc->data_bits++;
6008c2ecf20Sopenharmony_ci			}
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci		if (hdlc->data_bits == 8) {
6038c2ecf20Sopenharmony_ci			/* the code is for bitreverse streams */
6048c2ecf20Sopenharmony_ci			if (hdlc->do_bitreverse == 0)
6058c2ecf20Sopenharmony_ci				*dst++ = bitrev8(hdlc->cbin);
6068c2ecf20Sopenharmony_ci			else
6078c2ecf20Sopenharmony_ci				*dst++ = hdlc->cbin;
6088c2ecf20Sopenharmony_ci			hdlc->data_bits = 0;
6098c2ecf20Sopenharmony_ci			len++;
6108c2ecf20Sopenharmony_ci			dsize--;
6118c2ecf20Sopenharmony_ci		}
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	*count -= slen;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return len;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_encode);
618