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