xref: /linux/drivers/isdn/hardware/mISDN/isdnhdlc.c (revision df561f66)
18a7e8ff8SDavid S. Miller // SPDX-License-Identifier: GPL-2.0-or-later
299c2aa15SArnd Bergmann /*
399c2aa15SArnd Bergmann  * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
499c2aa15SArnd Bergmann  *
599c2aa15SArnd Bergmann  * Copyright (C)
699c2aa15SArnd Bergmann  *	2009	Karsten Keil		<keil@b1-systems.de>
799c2aa15SArnd Bergmann  *	2002	Wolfgang Mües		<wolfgang@iksw-muees.de>
899c2aa15SArnd Bergmann  *	2001	Frode Isaksen		<fisaksen@bewan.com>
999c2aa15SArnd Bergmann  *      2001	Kai Germaschewski	<kai.germaschewski@gmx.de>
1099c2aa15SArnd Bergmann  */
1199c2aa15SArnd Bergmann 
1299c2aa15SArnd Bergmann #include <linux/module.h>
1399c2aa15SArnd Bergmann #include <linux/init.h>
1499c2aa15SArnd Bergmann #include <linux/crc-ccitt.h>
1599c2aa15SArnd Bergmann #include <linux/bitrev.h>
1699c2aa15SArnd Bergmann #include "isdnhdlc.h"
1799c2aa15SArnd Bergmann 
1899c2aa15SArnd Bergmann /*-------------------------------------------------------------------*/
1999c2aa15SArnd Bergmann 
2099c2aa15SArnd Bergmann MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
2199c2aa15SArnd Bergmann 	      "Frode Isaksen <fisaksen@bewan.com>, "
2299c2aa15SArnd Bergmann 	      "Kai Germaschewski <kai.germaschewski@gmx.de>");
2399c2aa15SArnd Bergmann MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
2499c2aa15SArnd Bergmann MODULE_LICENSE("GPL");
2599c2aa15SArnd Bergmann 
2699c2aa15SArnd Bergmann /*-------------------------------------------------------------------*/
2799c2aa15SArnd Bergmann 
2899c2aa15SArnd Bergmann enum {
2999c2aa15SArnd Bergmann 	HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
3099c2aa15SArnd Bergmann 	HDLC_GET_DATA, HDLC_FAST_FLAG
3199c2aa15SArnd Bergmann };
3299c2aa15SArnd Bergmann 
3399c2aa15SArnd Bergmann enum {
3499c2aa15SArnd Bergmann 	HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
3599c2aa15SArnd Bergmann 	HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
3699c2aa15SArnd Bergmann 	HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
3799c2aa15SArnd Bergmann 	HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
3899c2aa15SArnd Bergmann };
3999c2aa15SArnd Bergmann 
isdnhdlc_rcv_init(struct isdnhdlc_vars * hdlc,u32 features)4099c2aa15SArnd Bergmann void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
4199c2aa15SArnd Bergmann {
4299c2aa15SArnd Bergmann 	memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
4399c2aa15SArnd Bergmann 	hdlc->state = HDLC_GET_DATA;
4499c2aa15SArnd Bergmann 	if (features & HDLC_56KBIT)
4599c2aa15SArnd Bergmann 		hdlc->do_adapt56 = 1;
4699c2aa15SArnd Bergmann 	if (features & HDLC_BITREVERSE)
4799c2aa15SArnd Bergmann 		hdlc->do_bitreverse = 1;
4899c2aa15SArnd Bergmann }
4999c2aa15SArnd Bergmann EXPORT_SYMBOL(isdnhdlc_out_init);
5099c2aa15SArnd Bergmann 
isdnhdlc_out_init(struct isdnhdlc_vars * hdlc,u32 features)5199c2aa15SArnd Bergmann void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
5299c2aa15SArnd Bergmann {
5399c2aa15SArnd Bergmann 	memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
5499c2aa15SArnd Bergmann 	if (features & HDLC_DCHANNEL) {
5599c2aa15SArnd Bergmann 		hdlc->dchannel = 1;
5699c2aa15SArnd Bergmann 		hdlc->state = HDLC_SEND_FIRST_FLAG;
5799c2aa15SArnd Bergmann 	} else {
5899c2aa15SArnd Bergmann 		hdlc->dchannel = 0;
5999c2aa15SArnd Bergmann 		hdlc->state = HDLC_SEND_FAST_FLAG;
6099c2aa15SArnd Bergmann 		hdlc->ffvalue = 0x7e;
6199c2aa15SArnd Bergmann 	}
6299c2aa15SArnd Bergmann 	hdlc->cbin = 0x7e;
6399c2aa15SArnd Bergmann 	if (features & HDLC_56KBIT) {
6499c2aa15SArnd Bergmann 		hdlc->do_adapt56 = 1;
6599c2aa15SArnd Bergmann 		hdlc->state = HDLC_SENDFLAG_B0;
6699c2aa15SArnd Bergmann 	} else
6799c2aa15SArnd Bergmann 		hdlc->data_bits = 8;
6899c2aa15SArnd Bergmann 	if (features & HDLC_BITREVERSE)
6999c2aa15SArnd Bergmann 		hdlc->do_bitreverse = 1;
7099c2aa15SArnd Bergmann }
7199c2aa15SArnd Bergmann EXPORT_SYMBOL(isdnhdlc_rcv_init);
7299c2aa15SArnd Bergmann 
7399c2aa15SArnd Bergmann static int
check_frame(struct isdnhdlc_vars * hdlc)7499c2aa15SArnd Bergmann check_frame(struct isdnhdlc_vars *hdlc)
7599c2aa15SArnd Bergmann {
7699c2aa15SArnd Bergmann 	int status;
7799c2aa15SArnd Bergmann 
7899c2aa15SArnd Bergmann 	if (hdlc->dstpos < 2)	/* too small - framing error */
7999c2aa15SArnd Bergmann 		status = -HDLC_FRAMING_ERROR;
8099c2aa15SArnd Bergmann 	else if (hdlc->crc != 0xf0b8)	/* crc error */
8199c2aa15SArnd Bergmann 		status = -HDLC_CRC_ERROR;
8299c2aa15SArnd Bergmann 	else {
8399c2aa15SArnd Bergmann 		/* remove CRC */
8499c2aa15SArnd Bergmann 		hdlc->dstpos -= 2;
8599c2aa15SArnd Bergmann 		/* good frame */
8699c2aa15SArnd Bergmann 		status = hdlc->dstpos;
8799c2aa15SArnd Bergmann 	}
8899c2aa15SArnd Bergmann 	return status;
8999c2aa15SArnd Bergmann }
9099c2aa15SArnd Bergmann 
9199c2aa15SArnd Bergmann /*
9299c2aa15SArnd Bergmann   isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
9399c2aa15SArnd Bergmann 
9499c2aa15SArnd Bergmann   The source buffer is scanned for valid HDLC frames looking for
9599c2aa15SArnd Bergmann   flags (01111110) to indicate the start of a frame. If the start of
9699c2aa15SArnd Bergmann   the frame is found, the bit stuffing is removed (0 after 5 1's).
9799c2aa15SArnd Bergmann   When a new flag is found, the complete frame has been received
9899c2aa15SArnd Bergmann   and the CRC is checked.
9999c2aa15SArnd Bergmann   If a valid frame is found, the function returns the frame length
10099c2aa15SArnd Bergmann   excluding the CRC with the bit HDLC_END_OF_FRAME set.
10199c2aa15SArnd Bergmann   If the beginning of a valid frame is found, the function returns
10299c2aa15SArnd Bergmann   the length.
10399c2aa15SArnd Bergmann   If a framing error is found (too many 1s and not a flag) the function
10499c2aa15SArnd Bergmann   returns the length with the bit HDLC_FRAMING_ERROR set.
10599c2aa15SArnd Bergmann   If a CRC error is found the function returns the length with the
10699c2aa15SArnd Bergmann   bit HDLC_CRC_ERROR set.
10799c2aa15SArnd Bergmann   If the frame length exceeds the destination buffer size, the function
10899c2aa15SArnd Bergmann   returns the length with the bit HDLC_LENGTH_ERROR set.
10999c2aa15SArnd Bergmann 
11099c2aa15SArnd Bergmann   src - source buffer
11199c2aa15SArnd Bergmann   slen - source buffer length
11299c2aa15SArnd Bergmann   count - number of bytes removed (decoded) from the source buffer
11399c2aa15SArnd Bergmann   dst _ destination buffer
11499c2aa15SArnd Bergmann   dsize - destination buffer size
11599c2aa15SArnd Bergmann   returns - number of decoded bytes in the destination buffer and status
11699c2aa15SArnd Bergmann   flag.
11799c2aa15SArnd Bergmann */
isdnhdlc_decode(struct isdnhdlc_vars * hdlc,const u8 * src,int slen,int * count,u8 * dst,int dsize)11899c2aa15SArnd Bergmann int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
11999c2aa15SArnd Bergmann 		    int *count, u8 *dst, int dsize)
12099c2aa15SArnd Bergmann {
12199c2aa15SArnd Bergmann 	int status = 0;
12299c2aa15SArnd Bergmann 
12399c2aa15SArnd Bergmann 	static const unsigned char fast_flag[] = {
12499c2aa15SArnd Bergmann 		0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
12599c2aa15SArnd Bergmann 	};
12699c2aa15SArnd Bergmann 
12799c2aa15SArnd Bergmann 	static const unsigned char fast_flag_value[] = {
12899c2aa15SArnd Bergmann 		0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
12999c2aa15SArnd Bergmann 	};
13099c2aa15SArnd Bergmann 
13199c2aa15SArnd Bergmann 	static const unsigned char fast_abort[] = {
13299c2aa15SArnd Bergmann 		0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
13399c2aa15SArnd Bergmann 	};
13499c2aa15SArnd Bergmann 
13599c2aa15SArnd Bergmann #define handle_fast_flag(h)						\
13699c2aa15SArnd Bergmann 	do {								\
13799c2aa15SArnd Bergmann 		if (h->cbin == fast_flag[h->bit_shift]) {		\
13899c2aa15SArnd Bergmann 			h->ffvalue = fast_flag_value[h->bit_shift];	\
13999c2aa15SArnd Bergmann 			h->state = HDLC_FAST_FLAG;			\
14099c2aa15SArnd Bergmann 			h->ffbit_shift = h->bit_shift;			\
14199c2aa15SArnd Bergmann 			h->bit_shift = 1;				\
14299c2aa15SArnd Bergmann 		} else {						\
14399c2aa15SArnd Bergmann 			h->state = HDLC_GET_DATA;			\
14499c2aa15SArnd Bergmann 			h->data_received = 0;				\
14599c2aa15SArnd Bergmann 		}							\
14699c2aa15SArnd Bergmann 	} while (0)
14799c2aa15SArnd Bergmann 
14899c2aa15SArnd Bergmann #define handle_abort(h)						\
14999c2aa15SArnd Bergmann 	do {							\
15099c2aa15SArnd Bergmann 		h->shift_reg = fast_abort[h->ffbit_shift - 1];	\
15199c2aa15SArnd Bergmann 		h->hdlc_bits1 = h->ffbit_shift - 2;		\
15299c2aa15SArnd Bergmann 		if (h->hdlc_bits1 < 0)				\
15399c2aa15SArnd Bergmann 			h->hdlc_bits1 = 0;			\
15499c2aa15SArnd Bergmann 		h->data_bits = h->ffbit_shift - 1;		\
15599c2aa15SArnd Bergmann 		h->state = HDLC_GET_DATA;			\
15699c2aa15SArnd Bergmann 		h->data_received = 0;				\
15799c2aa15SArnd Bergmann 	} while (0)
15899c2aa15SArnd Bergmann 
15999c2aa15SArnd Bergmann 	*count = slen;
16099c2aa15SArnd Bergmann 
16199c2aa15SArnd Bergmann 	while (slen > 0) {
16299c2aa15SArnd Bergmann 		if (hdlc->bit_shift == 0) {
16399c2aa15SArnd Bergmann 			/* the code is for bitreverse streams */
16499c2aa15SArnd Bergmann 			if (hdlc->do_bitreverse == 0)
16599c2aa15SArnd Bergmann 				hdlc->cbin = bitrev8(*src++);
16699c2aa15SArnd Bergmann 			else
16799c2aa15SArnd Bergmann 				hdlc->cbin = *src++;
16899c2aa15SArnd Bergmann 			slen--;
16999c2aa15SArnd Bergmann 			hdlc->bit_shift = 8;
17099c2aa15SArnd Bergmann 			if (hdlc->do_adapt56)
17199c2aa15SArnd Bergmann 				hdlc->bit_shift--;
17299c2aa15SArnd Bergmann 		}
17399c2aa15SArnd Bergmann 
17499c2aa15SArnd Bergmann 		switch (hdlc->state) {
17599c2aa15SArnd Bergmann 		case STOPPED:
17699c2aa15SArnd Bergmann 			return 0;
17799c2aa15SArnd Bergmann 		case HDLC_FAST_IDLE:
17899c2aa15SArnd Bergmann 			if (hdlc->cbin == 0xff) {
17999c2aa15SArnd Bergmann 				hdlc->bit_shift = 0;
18099c2aa15SArnd Bergmann 				break;
18199c2aa15SArnd Bergmann 			}
18299c2aa15SArnd Bergmann 			hdlc->state = HDLC_GET_FLAG_B0;
18399c2aa15SArnd Bergmann 			hdlc->hdlc_bits1 = 0;
18499c2aa15SArnd Bergmann 			hdlc->bit_shift = 8;
18599c2aa15SArnd Bergmann 			break;
18699c2aa15SArnd Bergmann 		case HDLC_GET_FLAG_B0:
18799c2aa15SArnd Bergmann 			if (!(hdlc->cbin & 0x80)) {
18899c2aa15SArnd Bergmann 				hdlc->state = HDLC_GETFLAG_B1A6;
18999c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
19099c2aa15SArnd Bergmann 			} else {
19199c2aa15SArnd Bergmann 				if ((!hdlc->do_adapt56) &&
19299c2aa15SArnd Bergmann 				    (++hdlc->hdlc_bits1 >= 8) &&
19399c2aa15SArnd Bergmann 				    (hdlc->bit_shift == 1))
19499c2aa15SArnd Bergmann 					hdlc->state = HDLC_FAST_IDLE;
19599c2aa15SArnd Bergmann 			}
19699c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
19799c2aa15SArnd Bergmann 			hdlc->bit_shift--;
19899c2aa15SArnd Bergmann 			break;
19999c2aa15SArnd Bergmann 		case HDLC_GETFLAG_B1A6:
20099c2aa15SArnd Bergmann 			if (hdlc->cbin & 0x80) {
20199c2aa15SArnd Bergmann 				hdlc->hdlc_bits1++;
20299c2aa15SArnd Bergmann 				if (hdlc->hdlc_bits1 == 6)
20399c2aa15SArnd Bergmann 					hdlc->state = HDLC_GETFLAG_B7;
20499c2aa15SArnd Bergmann 			} else
20599c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
20699c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
20799c2aa15SArnd Bergmann 			hdlc->bit_shift--;
20899c2aa15SArnd Bergmann 			break;
20999c2aa15SArnd Bergmann 		case HDLC_GETFLAG_B7:
21099c2aa15SArnd Bergmann 			if (hdlc->cbin & 0x80) {
21199c2aa15SArnd Bergmann 				hdlc->state = HDLC_GET_FLAG_B0;
21299c2aa15SArnd Bergmann 			} else {
21399c2aa15SArnd Bergmann 				hdlc->state = HDLC_GET_DATA;
21499c2aa15SArnd Bergmann 				hdlc->crc = 0xffff;
21599c2aa15SArnd Bergmann 				hdlc->shift_reg = 0;
21699c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
21799c2aa15SArnd Bergmann 				hdlc->data_bits = 0;
21899c2aa15SArnd Bergmann 				hdlc->data_received = 0;
21999c2aa15SArnd Bergmann 			}
22099c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
22199c2aa15SArnd Bergmann 			hdlc->bit_shift--;
22299c2aa15SArnd Bergmann 			break;
22399c2aa15SArnd Bergmann 		case HDLC_GET_DATA:
22499c2aa15SArnd Bergmann 			if (hdlc->cbin & 0x80) {
22599c2aa15SArnd Bergmann 				hdlc->hdlc_bits1++;
22699c2aa15SArnd Bergmann 				switch (hdlc->hdlc_bits1) {
22799c2aa15SArnd Bergmann 				case 6:
22899c2aa15SArnd Bergmann 					break;
22999c2aa15SArnd Bergmann 				case 7:
23099c2aa15SArnd Bergmann 					if (hdlc->data_received)
23199c2aa15SArnd Bergmann 						/* bad frame */
23299c2aa15SArnd Bergmann 						status = -HDLC_FRAMING_ERROR;
23399c2aa15SArnd Bergmann 					if (!hdlc->do_adapt56) {
23499c2aa15SArnd Bergmann 						if (hdlc->cbin == fast_abort
23599c2aa15SArnd Bergmann 						    [hdlc->bit_shift + 1]) {
23699c2aa15SArnd Bergmann 							hdlc->state =
23799c2aa15SArnd Bergmann 								HDLC_FAST_IDLE;
23899c2aa15SArnd Bergmann 							hdlc->bit_shift = 1;
23999c2aa15SArnd Bergmann 							break;
24099c2aa15SArnd Bergmann 						}
24199c2aa15SArnd Bergmann 					} else
24299c2aa15SArnd Bergmann 						hdlc->state = HDLC_GET_FLAG_B0;
24399c2aa15SArnd Bergmann 					break;
24499c2aa15SArnd Bergmann 				default:
24599c2aa15SArnd Bergmann 					hdlc->shift_reg >>= 1;
24699c2aa15SArnd Bergmann 					hdlc->shift_reg |= 0x80;
24799c2aa15SArnd Bergmann 					hdlc->data_bits++;
24899c2aa15SArnd Bergmann 					break;
24999c2aa15SArnd Bergmann 				}
25099c2aa15SArnd Bergmann 			} else {
25199c2aa15SArnd Bergmann 				switch (hdlc->hdlc_bits1) {
25299c2aa15SArnd Bergmann 				case 5:
25399c2aa15SArnd Bergmann 					break;
25499c2aa15SArnd Bergmann 				case 6:
25599c2aa15SArnd Bergmann 					if (hdlc->data_received)
25699c2aa15SArnd Bergmann 						status = check_frame(hdlc);
25799c2aa15SArnd Bergmann 					hdlc->crc = 0xffff;
25899c2aa15SArnd Bergmann 					hdlc->shift_reg = 0;
25999c2aa15SArnd Bergmann 					hdlc->data_bits = 0;
26099c2aa15SArnd Bergmann 					if (!hdlc->do_adapt56)
26199c2aa15SArnd Bergmann 						handle_fast_flag(hdlc);
26299c2aa15SArnd Bergmann 					else {
26399c2aa15SArnd Bergmann 						hdlc->state = HDLC_GET_DATA;
26499c2aa15SArnd Bergmann 						hdlc->data_received = 0;
26599c2aa15SArnd Bergmann 					}
26699c2aa15SArnd Bergmann 					break;
26799c2aa15SArnd Bergmann 				default:
26899c2aa15SArnd Bergmann 					hdlc->shift_reg >>= 1;
26999c2aa15SArnd Bergmann 					hdlc->data_bits++;
27099c2aa15SArnd Bergmann 					break;
27199c2aa15SArnd Bergmann 				}
27299c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
27399c2aa15SArnd Bergmann 			}
27499c2aa15SArnd Bergmann 			if (status) {
27599c2aa15SArnd Bergmann 				hdlc->dstpos = 0;
27699c2aa15SArnd Bergmann 				*count -= slen;
27799c2aa15SArnd Bergmann 				hdlc->cbin <<= 1;
27899c2aa15SArnd Bergmann 				hdlc->bit_shift--;
27999c2aa15SArnd Bergmann 				return status;
28099c2aa15SArnd Bergmann 			}
28199c2aa15SArnd Bergmann 			if (hdlc->data_bits == 8) {
28299c2aa15SArnd Bergmann 				hdlc->data_bits = 0;
28399c2aa15SArnd Bergmann 				hdlc->data_received = 1;
28499c2aa15SArnd Bergmann 				hdlc->crc = crc_ccitt_byte(hdlc->crc,
28599c2aa15SArnd Bergmann 							   hdlc->shift_reg);
28699c2aa15SArnd Bergmann 
28799c2aa15SArnd Bergmann 				/* good byte received */
28899c2aa15SArnd Bergmann 				if (hdlc->dstpos < dsize)
28999c2aa15SArnd Bergmann 					dst[hdlc->dstpos++] = hdlc->shift_reg;
29099c2aa15SArnd Bergmann 				else {
29199c2aa15SArnd Bergmann 					/* frame too long */
29299c2aa15SArnd Bergmann 					status = -HDLC_LENGTH_ERROR;
29399c2aa15SArnd Bergmann 					hdlc->dstpos = 0;
29499c2aa15SArnd Bergmann 				}
29599c2aa15SArnd Bergmann 			}
29699c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
29799c2aa15SArnd Bergmann 			hdlc->bit_shift--;
29899c2aa15SArnd Bergmann 			break;
29999c2aa15SArnd Bergmann 		case HDLC_FAST_FLAG:
30099c2aa15SArnd Bergmann 			if (hdlc->cbin == hdlc->ffvalue) {
30199c2aa15SArnd Bergmann 				hdlc->bit_shift = 0;
30299c2aa15SArnd Bergmann 				break;
30399c2aa15SArnd Bergmann 			} else {
30499c2aa15SArnd Bergmann 				if (hdlc->cbin == 0xff) {
30599c2aa15SArnd Bergmann 					hdlc->state = HDLC_FAST_IDLE;
30699c2aa15SArnd Bergmann 					hdlc->bit_shift = 0;
30799c2aa15SArnd Bergmann 				} else if (hdlc->ffbit_shift == 8) {
30899c2aa15SArnd Bergmann 					hdlc->state = HDLC_GETFLAG_B7;
30999c2aa15SArnd Bergmann 					break;
31099c2aa15SArnd Bergmann 				} else
31199c2aa15SArnd Bergmann 					handle_abort(hdlc);
31299c2aa15SArnd Bergmann 			}
31399c2aa15SArnd Bergmann 			break;
31499c2aa15SArnd Bergmann 		default:
31599c2aa15SArnd Bergmann 			break;
31699c2aa15SArnd Bergmann 		}
31799c2aa15SArnd Bergmann 	}
31899c2aa15SArnd Bergmann 	*count -= slen;
31999c2aa15SArnd Bergmann 	return 0;
32099c2aa15SArnd Bergmann }
32199c2aa15SArnd Bergmann EXPORT_SYMBOL(isdnhdlc_decode);
32299c2aa15SArnd Bergmann /*
32399c2aa15SArnd Bergmann   isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
32499c2aa15SArnd Bergmann 
32599c2aa15SArnd Bergmann   The bit stream starts with a beginning flag (01111110). After
32699c2aa15SArnd Bergmann   that each byte is added to the bit stream with bit stuffing added
32799c2aa15SArnd Bergmann   (0 after 5 1's).
32899c2aa15SArnd Bergmann   When the last byte has been removed from the source buffer, the
32999c2aa15SArnd Bergmann   CRC (2 bytes is added) and the frame terminates with the ending flag.
33099c2aa15SArnd Bergmann   For the dchannel, the idle character (all 1's) is also added at the end.
33199c2aa15SArnd Bergmann   If this function is called with empty source buffer (slen=0), flags or
33299c2aa15SArnd Bergmann   idle character will be generated.
33399c2aa15SArnd Bergmann 
33499c2aa15SArnd Bergmann   src - source buffer
33599c2aa15SArnd Bergmann   slen - source buffer length
33699c2aa15SArnd Bergmann   count - number of bytes removed (encoded) from source buffer
33799c2aa15SArnd Bergmann   dst _ destination buffer
33899c2aa15SArnd Bergmann   dsize - destination buffer size
33999c2aa15SArnd Bergmann   returns - number of encoded bytes in the destination buffer
34099c2aa15SArnd Bergmann */
isdnhdlc_encode(struct isdnhdlc_vars * hdlc,const u8 * src,u16 slen,int * count,u8 * dst,int dsize)34199c2aa15SArnd Bergmann int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
34299c2aa15SArnd Bergmann 		    int *count, u8 *dst, int dsize)
34399c2aa15SArnd Bergmann {
34499c2aa15SArnd Bergmann 	static const unsigned char xfast_flag_value[] = {
34599c2aa15SArnd Bergmann 		0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
34699c2aa15SArnd Bergmann 	};
34799c2aa15SArnd Bergmann 
34899c2aa15SArnd Bergmann 	int len = 0;
34999c2aa15SArnd Bergmann 
35099c2aa15SArnd Bergmann 	*count = slen;
35199c2aa15SArnd Bergmann 
35299c2aa15SArnd Bergmann 	/* special handling for one byte frames */
35399c2aa15SArnd Bergmann 	if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
35499c2aa15SArnd Bergmann 		hdlc->state = HDLC_SENDFLAG_ONE;
35599c2aa15SArnd Bergmann 	while (dsize > 0) {
35699c2aa15SArnd Bergmann 		if (hdlc->bit_shift == 0) {
35799c2aa15SArnd Bergmann 			if (slen && !hdlc->do_closing) {
35899c2aa15SArnd Bergmann 				hdlc->shift_reg = *src++;
35999c2aa15SArnd Bergmann 				slen--;
36099c2aa15SArnd Bergmann 				if (slen == 0)
36199c2aa15SArnd Bergmann 					/* closing sequence, CRC + flag(s) */
36299c2aa15SArnd Bergmann 					hdlc->do_closing = 1;
36399c2aa15SArnd Bergmann 				hdlc->bit_shift = 8;
36499c2aa15SArnd Bergmann 			} else {
36599c2aa15SArnd Bergmann 				if (hdlc->state == HDLC_SEND_DATA) {
36699c2aa15SArnd Bergmann 					if (hdlc->data_received) {
36799c2aa15SArnd Bergmann 						hdlc->state = HDLC_SEND_CRC1;
36899c2aa15SArnd Bergmann 						hdlc->crc ^= 0xffff;
36999c2aa15SArnd Bergmann 						hdlc->bit_shift = 8;
37099c2aa15SArnd Bergmann 						hdlc->shift_reg =
37199c2aa15SArnd Bergmann 							hdlc->crc & 0xff;
37299c2aa15SArnd Bergmann 					} else if (!hdlc->do_adapt56)
37399c2aa15SArnd Bergmann 						hdlc->state =
37499c2aa15SArnd Bergmann 							HDLC_SEND_FAST_FLAG;
37599c2aa15SArnd Bergmann 					else
37699c2aa15SArnd Bergmann 						hdlc->state =
37799c2aa15SArnd Bergmann 							HDLC_SENDFLAG_B0;
37899c2aa15SArnd Bergmann 				}
37999c2aa15SArnd Bergmann 
38099c2aa15SArnd Bergmann 			}
38199c2aa15SArnd Bergmann 		}
38299c2aa15SArnd Bergmann 
38399c2aa15SArnd Bergmann 		switch (hdlc->state) {
38499c2aa15SArnd Bergmann 		case STOPPED:
38599c2aa15SArnd Bergmann 			while (dsize--)
38699c2aa15SArnd Bergmann 				*dst++ = 0xff;
38799c2aa15SArnd Bergmann 			return dsize;
38899c2aa15SArnd Bergmann 		case HDLC_SEND_FAST_FLAG:
38999c2aa15SArnd Bergmann 			hdlc->do_closing = 0;
39099c2aa15SArnd Bergmann 			if (slen == 0) {
39199c2aa15SArnd Bergmann 				/* the code is for bitreverse streams */
39299c2aa15SArnd Bergmann 				if (hdlc->do_bitreverse == 0)
39399c2aa15SArnd Bergmann 					*dst++ = bitrev8(hdlc->ffvalue);
39499c2aa15SArnd Bergmann 				else
39599c2aa15SArnd Bergmann 					*dst++ = hdlc->ffvalue;
39699c2aa15SArnd Bergmann 				len++;
39799c2aa15SArnd Bergmann 				dsize--;
39899c2aa15SArnd Bergmann 				break;
39999c2aa15SArnd Bergmann 			}
400*df561f66SGustavo A. R. Silva 			fallthrough;
40199c2aa15SArnd Bergmann 		case HDLC_SENDFLAG_ONE:
40299c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 8) {
40399c2aa15SArnd Bergmann 				hdlc->cbin = hdlc->ffvalue >>
40499c2aa15SArnd Bergmann 					(8 - hdlc->data_bits);
40599c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_DATA;
40699c2aa15SArnd Bergmann 				hdlc->crc = 0xffff;
40799c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
40899c2aa15SArnd Bergmann 				hdlc->data_received = 1;
40999c2aa15SArnd Bergmann 			}
41099c2aa15SArnd Bergmann 			break;
41199c2aa15SArnd Bergmann 		case HDLC_SENDFLAG_B0:
41299c2aa15SArnd Bergmann 			hdlc->do_closing = 0;
41399c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
41499c2aa15SArnd Bergmann 			hdlc->data_bits++;
41599c2aa15SArnd Bergmann 			hdlc->hdlc_bits1 = 0;
41699c2aa15SArnd Bergmann 			hdlc->state = HDLC_SENDFLAG_B1A6;
41799c2aa15SArnd Bergmann 			break;
41899c2aa15SArnd Bergmann 		case HDLC_SENDFLAG_B1A6:
41999c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
42099c2aa15SArnd Bergmann 			hdlc->data_bits++;
42199c2aa15SArnd Bergmann 			hdlc->cbin++;
42299c2aa15SArnd Bergmann 			if (++hdlc->hdlc_bits1 == 6)
42399c2aa15SArnd Bergmann 				hdlc->state = HDLC_SENDFLAG_B7;
42499c2aa15SArnd Bergmann 			break;
42599c2aa15SArnd Bergmann 		case HDLC_SENDFLAG_B7:
42699c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
42799c2aa15SArnd Bergmann 			hdlc->data_bits++;
42899c2aa15SArnd Bergmann 			if (slen == 0) {
42999c2aa15SArnd Bergmann 				hdlc->state = HDLC_SENDFLAG_B0;
43099c2aa15SArnd Bergmann 				break;
43199c2aa15SArnd Bergmann 			}
43299c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 8) {
43399c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_DATA;
43499c2aa15SArnd Bergmann 				hdlc->crc = 0xffff;
43599c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
43699c2aa15SArnd Bergmann 				hdlc->data_received = 1;
43799c2aa15SArnd Bergmann 			}
43899c2aa15SArnd Bergmann 			break;
43999c2aa15SArnd Bergmann 		case HDLC_SEND_FIRST_FLAG:
44099c2aa15SArnd Bergmann 			hdlc->data_received = 1;
44199c2aa15SArnd Bergmann 			if (hdlc->data_bits == 8) {
44299c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_DATA;
44399c2aa15SArnd Bergmann 				hdlc->crc = 0xffff;
44499c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
44599c2aa15SArnd Bergmann 				break;
44699c2aa15SArnd Bergmann 			}
44799c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
44899c2aa15SArnd Bergmann 			hdlc->data_bits++;
44999c2aa15SArnd Bergmann 			if (hdlc->shift_reg & 0x01)
45099c2aa15SArnd Bergmann 				hdlc->cbin++;
45199c2aa15SArnd Bergmann 			hdlc->shift_reg >>= 1;
45299c2aa15SArnd Bergmann 			hdlc->bit_shift--;
45399c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 0) {
45499c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_DATA;
45599c2aa15SArnd Bergmann 				hdlc->crc = 0xffff;
45699c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
45799c2aa15SArnd Bergmann 			}
45899c2aa15SArnd Bergmann 			break;
45999c2aa15SArnd Bergmann 		case HDLC_SEND_DATA:
46099c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
46199c2aa15SArnd Bergmann 			hdlc->data_bits++;
46299c2aa15SArnd Bergmann 			if (hdlc->hdlc_bits1 == 5) {
46399c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
46499c2aa15SArnd Bergmann 				break;
46599c2aa15SArnd Bergmann 			}
46699c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 8)
46799c2aa15SArnd Bergmann 				hdlc->crc = crc_ccitt_byte(hdlc->crc,
46899c2aa15SArnd Bergmann 							   hdlc->shift_reg);
46999c2aa15SArnd Bergmann 			if (hdlc->shift_reg & 0x01) {
47099c2aa15SArnd Bergmann 				hdlc->hdlc_bits1++;
47199c2aa15SArnd Bergmann 				hdlc->cbin++;
47299c2aa15SArnd Bergmann 				hdlc->shift_reg >>= 1;
47399c2aa15SArnd Bergmann 				hdlc->bit_shift--;
47499c2aa15SArnd Bergmann 			} else {
47599c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
47699c2aa15SArnd Bergmann 				hdlc->shift_reg >>= 1;
47799c2aa15SArnd Bergmann 				hdlc->bit_shift--;
47899c2aa15SArnd Bergmann 			}
47999c2aa15SArnd Bergmann 			break;
48099c2aa15SArnd Bergmann 		case HDLC_SEND_CRC1:
48199c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
48299c2aa15SArnd Bergmann 			hdlc->data_bits++;
48399c2aa15SArnd Bergmann 			if (hdlc->hdlc_bits1 == 5) {
48499c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
48599c2aa15SArnd Bergmann 				break;
48699c2aa15SArnd Bergmann 			}
48799c2aa15SArnd Bergmann 			if (hdlc->shift_reg & 0x01) {
48899c2aa15SArnd Bergmann 				hdlc->hdlc_bits1++;
48999c2aa15SArnd Bergmann 				hdlc->cbin++;
49099c2aa15SArnd Bergmann 				hdlc->shift_reg >>= 1;
49199c2aa15SArnd Bergmann 				hdlc->bit_shift--;
49299c2aa15SArnd Bergmann 			} else {
49399c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
49499c2aa15SArnd Bergmann 				hdlc->shift_reg >>= 1;
49599c2aa15SArnd Bergmann 				hdlc->bit_shift--;
49699c2aa15SArnd Bergmann 			}
49799c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 0) {
49899c2aa15SArnd Bergmann 				hdlc->shift_reg = (hdlc->crc >> 8);
49999c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_CRC2;
50099c2aa15SArnd Bergmann 				hdlc->bit_shift = 8;
50199c2aa15SArnd Bergmann 			}
50299c2aa15SArnd Bergmann 			break;
50399c2aa15SArnd Bergmann 		case HDLC_SEND_CRC2:
50499c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
50599c2aa15SArnd Bergmann 			hdlc->data_bits++;
50699c2aa15SArnd Bergmann 			if (hdlc->hdlc_bits1 == 5) {
50799c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
50899c2aa15SArnd Bergmann 				break;
50999c2aa15SArnd Bergmann 			}
51099c2aa15SArnd Bergmann 			if (hdlc->shift_reg & 0x01) {
51199c2aa15SArnd Bergmann 				hdlc->hdlc_bits1++;
51299c2aa15SArnd Bergmann 				hdlc->cbin++;
51399c2aa15SArnd Bergmann 				hdlc->shift_reg >>= 1;
51499c2aa15SArnd Bergmann 				hdlc->bit_shift--;
51599c2aa15SArnd Bergmann 			} else {
51699c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
51799c2aa15SArnd Bergmann 				hdlc->shift_reg >>= 1;
51899c2aa15SArnd Bergmann 				hdlc->bit_shift--;
51999c2aa15SArnd Bergmann 			}
52099c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 0) {
52199c2aa15SArnd Bergmann 				hdlc->shift_reg = 0x7e;
52299c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_CLOSING_FLAG;
52399c2aa15SArnd Bergmann 				hdlc->bit_shift = 8;
52499c2aa15SArnd Bergmann 			}
52599c2aa15SArnd Bergmann 			break;
52699c2aa15SArnd Bergmann 		case HDLC_SEND_CLOSING_FLAG:
52799c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
52899c2aa15SArnd Bergmann 			hdlc->data_bits++;
52999c2aa15SArnd Bergmann 			if (hdlc->hdlc_bits1 == 5) {
53099c2aa15SArnd Bergmann 				hdlc->hdlc_bits1 = 0;
53199c2aa15SArnd Bergmann 				break;
53299c2aa15SArnd Bergmann 			}
53399c2aa15SArnd Bergmann 			if (hdlc->shift_reg & 0x01)
53499c2aa15SArnd Bergmann 				hdlc->cbin++;
53599c2aa15SArnd Bergmann 			hdlc->shift_reg >>= 1;
53699c2aa15SArnd Bergmann 			hdlc->bit_shift--;
53799c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 0) {
53899c2aa15SArnd Bergmann 				hdlc->ffvalue =
53999c2aa15SArnd Bergmann 					xfast_flag_value[hdlc->data_bits];
54099c2aa15SArnd Bergmann 				if (hdlc->dchannel) {
54199c2aa15SArnd Bergmann 					hdlc->ffvalue = 0x7e;
54299c2aa15SArnd Bergmann 					hdlc->state = HDLC_SEND_IDLE1;
54399c2aa15SArnd Bergmann 					hdlc->bit_shift = 8-hdlc->data_bits;
54499c2aa15SArnd Bergmann 					if (hdlc->bit_shift == 0)
54599c2aa15SArnd Bergmann 						hdlc->state =
54699c2aa15SArnd Bergmann 							HDLC_SEND_FAST_IDLE;
54799c2aa15SArnd Bergmann 				} else {
54899c2aa15SArnd Bergmann 					if (!hdlc->do_adapt56) {
54999c2aa15SArnd Bergmann 						hdlc->state =
55099c2aa15SArnd Bergmann 							HDLC_SEND_FAST_FLAG;
55199c2aa15SArnd Bergmann 						hdlc->data_received = 0;
55299c2aa15SArnd Bergmann 					} else {
55399c2aa15SArnd Bergmann 						hdlc->state = HDLC_SENDFLAG_B0;
55499c2aa15SArnd Bergmann 						hdlc->data_received = 0;
55599c2aa15SArnd Bergmann 					}
55699c2aa15SArnd Bergmann 					/* Finished this frame, send flags */
55799c2aa15SArnd Bergmann 					if (dsize > 1)
55899c2aa15SArnd Bergmann 						dsize = 1;
55999c2aa15SArnd Bergmann 				}
56099c2aa15SArnd Bergmann 			}
56199c2aa15SArnd Bergmann 			break;
56299c2aa15SArnd Bergmann 		case HDLC_SEND_IDLE1:
56399c2aa15SArnd Bergmann 			hdlc->do_closing = 0;
56499c2aa15SArnd Bergmann 			hdlc->cbin <<= 1;
56599c2aa15SArnd Bergmann 			hdlc->cbin++;
56699c2aa15SArnd Bergmann 			hdlc->data_bits++;
56799c2aa15SArnd Bergmann 			hdlc->bit_shift--;
56899c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 0) {
56999c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_FAST_IDLE;
57099c2aa15SArnd Bergmann 				hdlc->bit_shift = 0;
57199c2aa15SArnd Bergmann 			}
57299c2aa15SArnd Bergmann 			break;
57399c2aa15SArnd Bergmann 		case HDLC_SEND_FAST_IDLE:
57499c2aa15SArnd Bergmann 			hdlc->do_closing = 0;
57599c2aa15SArnd Bergmann 			hdlc->cbin = 0xff;
57699c2aa15SArnd Bergmann 			hdlc->data_bits = 8;
57799c2aa15SArnd Bergmann 			if (hdlc->bit_shift == 8) {
57899c2aa15SArnd Bergmann 				hdlc->cbin = 0x7e;
57999c2aa15SArnd Bergmann 				hdlc->state = HDLC_SEND_FIRST_FLAG;
58099c2aa15SArnd Bergmann 			} else {
58199c2aa15SArnd Bergmann 				/* the code is for bitreverse streams */
58299c2aa15SArnd Bergmann 				if (hdlc->do_bitreverse == 0)
58399c2aa15SArnd Bergmann 					*dst++ = bitrev8(hdlc->cbin);
58499c2aa15SArnd Bergmann 				else
58599c2aa15SArnd Bergmann 					*dst++ = hdlc->cbin;
58699c2aa15SArnd Bergmann 				hdlc->bit_shift = 0;
58799c2aa15SArnd Bergmann 				hdlc->data_bits = 0;
58899c2aa15SArnd Bergmann 				len++;
58999c2aa15SArnd Bergmann 				dsize = 0;
59099c2aa15SArnd Bergmann 			}
59199c2aa15SArnd Bergmann 			break;
59299c2aa15SArnd Bergmann 		default:
59399c2aa15SArnd Bergmann 			break;
59499c2aa15SArnd Bergmann 		}
59599c2aa15SArnd Bergmann 		if (hdlc->do_adapt56) {
59699c2aa15SArnd Bergmann 			if (hdlc->data_bits == 7) {
59799c2aa15SArnd Bergmann 				hdlc->cbin <<= 1;
59899c2aa15SArnd Bergmann 				hdlc->cbin++;
59999c2aa15SArnd Bergmann 				hdlc->data_bits++;
60099c2aa15SArnd Bergmann 			}
60199c2aa15SArnd Bergmann 		}
60299c2aa15SArnd Bergmann 		if (hdlc->data_bits == 8) {
60399c2aa15SArnd Bergmann 			/* the code is for bitreverse streams */
60499c2aa15SArnd Bergmann 			if (hdlc->do_bitreverse == 0)
60599c2aa15SArnd Bergmann 				*dst++ = bitrev8(hdlc->cbin);
60699c2aa15SArnd Bergmann 			else
60799c2aa15SArnd Bergmann 				*dst++ = hdlc->cbin;
60899c2aa15SArnd Bergmann 			hdlc->data_bits = 0;
60999c2aa15SArnd Bergmann 			len++;
61099c2aa15SArnd Bergmann 			dsize--;
61199c2aa15SArnd Bergmann 		}
61299c2aa15SArnd Bergmann 	}
61399c2aa15SArnd Bergmann 	*count -= slen;
61499c2aa15SArnd Bergmann 
61599c2aa15SArnd Bergmann 	return len;
61699c2aa15SArnd Bergmann }
61799c2aa15SArnd Bergmann EXPORT_SYMBOL(isdnhdlc_encode);
618