2 * isdnhdlc.c -- General purpose ISDN HDLC decoder.
4 *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
5 * 2001 Frode Isaksen <fisaksen@bewan.com>
6 * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/crc-ccitt.h>
28 /*-------------------------------------------------------------------*/
30 MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
31 "Frode Isaksen <fisaksen@bewan.com>, "
32 "Kai Germaschewski <kai.germaschewski@gmx.de>");
33 MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
34 MODULE_LICENSE("GPL");
36 /*-------------------------------------------------------------------*/
39 * Very handy for devices with different bit order,
40 * and neccessary for each transparent B-channel access for all
41 * devices which works with this HDLC decoder without bit reversal.
43 const unsigned char isdnhdlc_bit_rev_tab
[256] = {
44 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
45 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
46 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
47 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
48 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
49 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
50 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
51 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
52 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
53 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
54 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
55 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
56 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
57 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
58 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
59 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
63 HDLC_FAST_IDLE
,HDLC_GET_FLAG_B0
,HDLC_GETFLAG_B1A6
,HDLC_GETFLAG_B7
,
64 HDLC_GET_DATA
,HDLC_FAST_FLAG
68 HDLC_SEND_DATA
,HDLC_SEND_CRC1
,HDLC_SEND_FAST_FLAG
,
69 HDLC_SEND_FIRST_FLAG
,HDLC_SEND_CRC2
,HDLC_SEND_CLOSING_FLAG
,
70 HDLC_SEND_IDLE1
,HDLC_SEND_FAST_IDLE
,HDLC_SENDFLAG_B0
,
71 HDLC_SENDFLAG_B1A6
,HDLC_SENDFLAG_B7
,STOPPED
74 void isdnhdlc_rcv_init (struct isdnhdlc_vars
*hdlc
, int do_adapt56
)
79 hdlc
->ffbit_shift
= 0;
80 hdlc
->data_received
= 0;
81 hdlc
->state
= HDLC_GET_DATA
;
82 hdlc
->do_adapt56
= do_adapt56
;
91 void isdnhdlc_out_init (struct isdnhdlc_vars
*hdlc
, int is_d_channel
, int do_adapt56
)
96 hdlc
->ffbit_shift
= 0;
97 hdlc
->data_received
= 0;
102 hdlc
->state
= HDLC_SEND_FIRST_FLAG
;
105 hdlc
->state
= HDLC_SEND_FAST_FLAG
;
106 hdlc
->ffvalue
= 0x7e;
111 hdlc
->do_adapt56
= 1;
113 hdlc
->state
= HDLC_SENDFLAG_B0
;
115 hdlc
->do_adapt56
= 0;
122 isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
124 The source buffer is scanned for valid HDLC frames looking for
125 flags (01111110) to indicate the start of a frame. If the start of
126 the frame is found, the bit stuffing is removed (0 after 5 1's).
127 When a new flag is found, the complete frame has been received
128 and the CRC is checked.
129 If a valid frame is found, the function returns the frame length
130 excluding the CRC with the bit HDLC_END_OF_FRAME set.
131 If the beginning of a valid frame is found, the function returns
133 If a framing error is found (too many 1s and not a flag) the function
134 returns the length with the bit HDLC_FRAMING_ERROR set.
135 If a CRC error is found the function returns the length with the
136 bit HDLC_CRC_ERROR set.
137 If the frame length exceeds the destination buffer size, the function
138 returns the length with the bit HDLC_LENGTH_ERROR set.
141 slen - source buffer length
142 count - number of bytes removed (decoded) from the source buffer
143 dst _ destination buffer
144 dsize - destination buffer size
145 returns - number of decoded bytes in the destination buffer and status
148 int isdnhdlc_decode (struct isdnhdlc_vars
*hdlc
, const unsigned char *src
,
149 int slen
, int *count
, unsigned char *dst
, int dsize
)
153 static const unsigned char fast_flag
[]={
154 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
157 static const unsigned char fast_flag_value
[]={
158 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
161 static const unsigned char fast_abort
[]={
162 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
168 if(hdlc
->bit_shift
==0){
172 if(hdlc
->do_adapt56
){
181 if(hdlc
->cbin
== 0xff){
185 hdlc
->state
= HDLC_GET_FLAG_B0
;
186 hdlc
->hdlc_bits1
= 0;
189 case HDLC_GET_FLAG_B0
:
190 if(!(hdlc
->cbin
& 0x80)) {
191 hdlc
->state
= HDLC_GETFLAG_B1A6
;
192 hdlc
->hdlc_bits1
= 0;
194 if(!hdlc
->do_adapt56
){
195 if(++hdlc
->hdlc_bits1
>=8 ) if(hdlc
->bit_shift
==1)
196 hdlc
->state
= HDLC_FAST_IDLE
;
202 case HDLC_GETFLAG_B1A6
:
203 if(hdlc
->cbin
& 0x80){
205 if(hdlc
->hdlc_bits1
==6){
206 hdlc
->state
= HDLC_GETFLAG_B7
;
209 hdlc
->hdlc_bits1
= 0;
214 case HDLC_GETFLAG_B7
:
215 if(hdlc
->cbin
& 0x80) {
216 hdlc
->state
= HDLC_GET_FLAG_B0
;
218 hdlc
->state
= HDLC_GET_DATA
;
221 hdlc
->hdlc_bits1
= 0;
223 hdlc
->data_received
= 0;
229 if(hdlc
->cbin
& 0x80){
231 switch(hdlc
->hdlc_bits1
){
235 if(hdlc
->data_received
) {
237 status
= -HDLC_FRAMING_ERROR
;
239 if(!hdlc
->do_adapt56
){
240 if(hdlc
->cbin
==fast_abort
[hdlc
->bit_shift
+1]){
241 hdlc
->state
= HDLC_FAST_IDLE
;
246 hdlc
->state
= HDLC_GET_FLAG_B0
;
251 hdlc
->shift_reg
|= 0x80;
256 switch(hdlc
->hdlc_bits1
){
260 if(hdlc
->data_received
){
261 if (hdlc
->dstpos
< 2) {
262 status
= -HDLC_FRAMING_ERROR
;
263 } else if (hdlc
->crc
!= 0xf0b8){
265 status
= -HDLC_CRC_ERROR
;
270 status
= hdlc
->dstpos
;
276 if(!hdlc
->do_adapt56
){
277 if(hdlc
->cbin
==fast_flag
[hdlc
->bit_shift
]){
278 hdlc
->ffvalue
= fast_flag_value
[hdlc
->bit_shift
];
279 hdlc
->state
= HDLC_FAST_FLAG
;
280 hdlc
->ffbit_shift
= hdlc
->bit_shift
;
283 hdlc
->state
= HDLC_GET_DATA
;
284 hdlc
->data_received
= 0;
287 hdlc
->state
= HDLC_GET_DATA
;
288 hdlc
->data_received
= 0;
296 hdlc
->hdlc_bits1
= 0;
305 if(hdlc
->data_bits
==8){
307 hdlc
->data_received
= 1;
308 hdlc
->crc
= crc_ccitt_byte(hdlc
->crc
, hdlc
->shift_reg
);
310 // good byte received
311 if (hdlc
->dstpos
< dsize
) {
312 dst
[hdlc
->dstpos
++] = hdlc
->shift_reg
;
315 status
= -HDLC_LENGTH_ERROR
;
323 if(hdlc
->cbin
==hdlc
->ffvalue
){
327 if(hdlc
->cbin
== 0xff){
328 hdlc
->state
= HDLC_FAST_IDLE
;
330 } else if(hdlc
->ffbit_shift
==8){
331 hdlc
->state
= HDLC_GETFLAG_B7
;
334 hdlc
->shift_reg
= fast_abort
[hdlc
->ffbit_shift
-1];
335 hdlc
->hdlc_bits1
= hdlc
->ffbit_shift
-2;
336 if(hdlc
->hdlc_bits1
<0)hdlc
->hdlc_bits1
= 0;
337 hdlc
->data_bits
= hdlc
->ffbit_shift
-1;
338 hdlc
->state
= HDLC_GET_DATA
;
339 hdlc
->data_received
= 0;
352 isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
354 The bit stream starts with a beginning flag (01111110). After
355 that each byte is added to the bit stream with bit stuffing added
357 When the last byte has been removed from the source buffer, the
358 CRC (2 bytes is added) and the frame terminates with the ending flag.
359 For the dchannel, the idle character (all 1's) is also added at the end.
360 If this function is called with empty source buffer (slen=0), flags or
361 idle character will be generated.
364 slen - source buffer length
365 count - number of bytes removed (encoded) from source buffer
366 dst _ destination buffer
367 dsize - destination buffer size
368 returns - number of encoded bytes in the destination buffer
370 int isdnhdlc_encode(struct isdnhdlc_vars
*hdlc
, const unsigned char *src
,
371 unsigned short slen
, int *count
,
372 unsigned char *dst
, int dsize
)
374 static const unsigned char xfast_flag_value
[] = {
375 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
383 if(hdlc
->bit_shift
==0){
384 if(slen
&& !hdlc
->do_closing
){
385 hdlc
->shift_reg
= *src
++;
388 hdlc
->do_closing
= 1; /* closing sequence, CRC + flag(s) */
391 if(hdlc
->state
== HDLC_SEND_DATA
){
392 if(hdlc
->data_received
){
393 hdlc
->state
= HDLC_SEND_CRC1
;
396 hdlc
->shift_reg
= hdlc
->crc
& 0xff;
397 } else if(!hdlc
->do_adapt56
){
398 hdlc
->state
= HDLC_SEND_FAST_FLAG
;
400 hdlc
->state
= HDLC_SENDFLAG_B0
;
413 case HDLC_SEND_FAST_FLAG
:
414 hdlc
->do_closing
= 0;
416 *dst
++ = hdlc
->ffvalue
;
421 if(hdlc
->bit_shift
==8){
422 hdlc
->cbin
= hdlc
->ffvalue
>>(8-hdlc
->data_bits
);
423 hdlc
->state
= HDLC_SEND_DATA
;
425 hdlc
->hdlc_bits1
= 0;
426 hdlc
->data_received
= 1;
429 case HDLC_SENDFLAG_B0
:
430 hdlc
->do_closing
= 0;
433 hdlc
->hdlc_bits1
= 0;
434 hdlc
->state
= HDLC_SENDFLAG_B1A6
;
436 case HDLC_SENDFLAG_B1A6
:
440 if(++hdlc
->hdlc_bits1
== 6)
441 hdlc
->state
= HDLC_SENDFLAG_B7
;
443 case HDLC_SENDFLAG_B7
:
447 hdlc
->state
= HDLC_SENDFLAG_B0
;
450 if(hdlc
->bit_shift
==8){
451 hdlc
->state
= HDLC_SEND_DATA
;
453 hdlc
->hdlc_bits1
= 0;
454 hdlc
->data_received
= 1;
457 case HDLC_SEND_FIRST_FLAG
:
458 hdlc
->data_received
= 1;
459 if(hdlc
->data_bits
==8){
460 hdlc
->state
= HDLC_SEND_DATA
;
462 hdlc
->hdlc_bits1
= 0;
467 if(hdlc
->shift_reg
& 0x01)
469 hdlc
->shift_reg
>>= 1;
471 if(hdlc
->bit_shift
==0){
472 hdlc
->state
= HDLC_SEND_DATA
;
474 hdlc
->hdlc_bits1
= 0;
480 if(hdlc
->hdlc_bits1
== 5){
481 hdlc
->hdlc_bits1
= 0;
484 if(hdlc
->bit_shift
==8){
485 hdlc
->crc
= crc_ccitt_byte(hdlc
->crc
, hdlc
->shift_reg
);
487 if(hdlc
->shift_reg
& 0x01){
490 hdlc
->shift_reg
>>= 1;
493 hdlc
->hdlc_bits1
= 0;
494 hdlc
->shift_reg
>>= 1;
501 if(hdlc
->hdlc_bits1
== 5){
502 hdlc
->hdlc_bits1
= 0;
505 if(hdlc
->shift_reg
& 0x01){
508 hdlc
->shift_reg
>>= 1;
511 hdlc
->hdlc_bits1
= 0;
512 hdlc
->shift_reg
>>= 1;
515 if(hdlc
->bit_shift
==0){
516 hdlc
->shift_reg
= (hdlc
->crc
>> 8);
517 hdlc
->state
= HDLC_SEND_CRC2
;
524 if(hdlc
->hdlc_bits1
== 5){
525 hdlc
->hdlc_bits1
= 0;
528 if(hdlc
->shift_reg
& 0x01){
531 hdlc
->shift_reg
>>= 1;
534 hdlc
->hdlc_bits1
= 0;
535 hdlc
->shift_reg
>>= 1;
538 if(hdlc
->bit_shift
==0){
539 hdlc
->shift_reg
= 0x7e;
540 hdlc
->state
= HDLC_SEND_CLOSING_FLAG
;
544 case HDLC_SEND_CLOSING_FLAG
:
547 if(hdlc
->hdlc_bits1
== 5){
548 hdlc
->hdlc_bits1
= 0;
551 if(hdlc
->shift_reg
& 0x01){
554 hdlc
->shift_reg
>>= 1;
556 if(hdlc
->bit_shift
==0){
557 hdlc
->ffvalue
= xfast_flag_value
[hdlc
->data_bits
];
559 hdlc
->ffvalue
= 0x7e;
560 hdlc
->state
= HDLC_SEND_IDLE1
;
561 hdlc
->bit_shift
= 8-hdlc
->data_bits
;
562 if(hdlc
->bit_shift
==0)
563 hdlc
->state
= HDLC_SEND_FAST_IDLE
;
565 if(!hdlc
->do_adapt56
){
566 hdlc
->state
= HDLC_SEND_FAST_FLAG
;
567 hdlc
->data_received
= 0;
569 hdlc
->state
= HDLC_SENDFLAG_B0
;
570 hdlc
->data_received
= 0;
572 // Finished with this frame, send flags
573 if (dsize
> 1) dsize
= 1;
577 case HDLC_SEND_IDLE1
:
578 hdlc
->do_closing
= 0;
583 if(hdlc
->bit_shift
==0){
584 hdlc
->state
= HDLC_SEND_FAST_IDLE
;
588 case HDLC_SEND_FAST_IDLE
:
589 hdlc
->do_closing
= 0;
592 if(hdlc
->bit_shift
== 8){
594 hdlc
->state
= HDLC_SEND_FIRST_FLAG
;
597 hdlc
->bit_shift
= hdlc
->data_bits
= 0;
605 if(hdlc
->do_adapt56
){
606 if(hdlc
->data_bits
==7){
612 if(hdlc
->data_bits
==8){
624 EXPORT_SYMBOL(isdnhdlc_bit_rev_tab
);
625 EXPORT_SYMBOL(isdnhdlc_rcv_init
);
626 EXPORT_SYMBOL(isdnhdlc_decode
);
627 EXPORT_SYMBOL(isdnhdlc_out_init
);
628 EXPORT_SYMBOL(isdnhdlc_encode
);