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 HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
40 HDLC_GET_DATA,HDLC_FAST_FLAG
44 HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
45 HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
46 HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
47 HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
50 void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
55 hdlc->ffbit_shift = 0;
56 hdlc->data_received = 0;
57 hdlc->state = HDLC_GET_DATA;
58 hdlc->do_adapt56 = do_adapt56;
67 void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
72 hdlc->ffbit_shift = 0;
73 hdlc->data_received = 0;
78 hdlc->state = HDLC_SEND_FIRST_FLAG;
81 hdlc->state = HDLC_SEND_FAST_FLAG;
89 hdlc->state = HDLC_SENDFLAG_B0;
98 isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
100 The source buffer is scanned for valid HDLC frames looking for
101 flags (01111110) to indicate the start of a frame. If the start of
102 the frame is found, the bit stuffing is removed (0 after 5 1's).
103 When a new flag is found, the complete frame has been received
104 and the CRC is checked.
105 If a valid frame is found, the function returns the frame length
106 excluding the CRC with the bit HDLC_END_OF_FRAME set.
107 If the beginning of a valid frame is found, the function returns
109 If a framing error is found (too many 1s and not a flag) the function
110 returns the length with the bit HDLC_FRAMING_ERROR set.
111 If a CRC error is found the function returns the length with the
112 bit HDLC_CRC_ERROR set.
113 If the frame length exceeds the destination buffer size, the function
114 returns the length with the bit HDLC_LENGTH_ERROR set.
117 slen - source buffer length
118 count - number of bytes removed (decoded) from the source buffer
119 dst _ destination buffer
120 dsize - destination buffer size
121 returns - number of decoded bytes in the destination buffer and status
124 int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
125 int slen, int *count, unsigned char *dst, int dsize)
129 static const unsigned char fast_flag[]={
130 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
133 static const unsigned char fast_flag_value[]={
134 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
137 static const unsigned char fast_abort[]={
138 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
144 if(hdlc->bit_shift==0){
148 if(hdlc->do_adapt56){
157 if(hdlc->cbin == 0xff){
161 hdlc->state = HDLC_GET_FLAG_B0;
162 hdlc->hdlc_bits1 = 0;
165 case HDLC_GET_FLAG_B0:
166 if(!(hdlc->cbin & 0x80)) {
167 hdlc->state = HDLC_GETFLAG_B1A6;
168 hdlc->hdlc_bits1 = 0;
170 if(!hdlc->do_adapt56){
171 if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
172 hdlc->state = HDLC_FAST_IDLE;
178 case HDLC_GETFLAG_B1A6:
179 if(hdlc->cbin & 0x80){
181 if(hdlc->hdlc_bits1==6){
182 hdlc->state = HDLC_GETFLAG_B7;
185 hdlc->hdlc_bits1 = 0;
190 case HDLC_GETFLAG_B7:
191 if(hdlc->cbin & 0x80) {
192 hdlc->state = HDLC_GET_FLAG_B0;
194 hdlc->state = HDLC_GET_DATA;
197 hdlc->hdlc_bits1 = 0;
199 hdlc->data_received = 0;
205 if(hdlc->cbin & 0x80){
207 switch(hdlc->hdlc_bits1){
211 if(hdlc->data_received) {
213 status = -HDLC_FRAMING_ERROR;
215 if(!hdlc->do_adapt56){
216 if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
217 hdlc->state = HDLC_FAST_IDLE;
222 hdlc->state = HDLC_GET_FLAG_B0;
227 hdlc->shift_reg |= 0x80;
232 switch(hdlc->hdlc_bits1){
236 if(hdlc->data_received){
237 if (hdlc->dstpos < 2) {
238 status = -HDLC_FRAMING_ERROR;
239 } else if (hdlc->crc != 0xf0b8){
241 status = -HDLC_CRC_ERROR;
246 status = hdlc->dstpos;
252 if(!hdlc->do_adapt56){
253 if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
254 hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
255 hdlc->state = HDLC_FAST_FLAG;
256 hdlc->ffbit_shift = hdlc->bit_shift;
259 hdlc->state = HDLC_GET_DATA;
260 hdlc->data_received = 0;
263 hdlc->state = HDLC_GET_DATA;
264 hdlc->data_received = 0;
272 hdlc->hdlc_bits1 = 0;
281 if(hdlc->data_bits==8){
283 hdlc->data_received = 1;
284 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
286 // good byte received
287 if (hdlc->dstpos < dsize) {
288 dst[hdlc->dstpos++] = hdlc->shift_reg;
291 status = -HDLC_LENGTH_ERROR;
299 if(hdlc->cbin==hdlc->ffvalue){
303 if(hdlc->cbin == 0xff){
304 hdlc->state = HDLC_FAST_IDLE;
306 } else if(hdlc->ffbit_shift==8){
307 hdlc->state = HDLC_GETFLAG_B7;
310 hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
311 hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
312 if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
313 hdlc->data_bits = hdlc->ffbit_shift-1;
314 hdlc->state = HDLC_GET_DATA;
315 hdlc->data_received = 0;
328 isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
330 The bit stream starts with a beginning flag (01111110). After
331 that each byte is added to the bit stream with bit stuffing added
333 When the last byte has been removed from the source buffer, the
334 CRC (2 bytes is added) and the frame terminates with the ending flag.
335 For the dchannel, the idle character (all 1's) is also added at the end.
336 If this function is called with empty source buffer (slen=0), flags or
337 idle character will be generated.
340 slen - source buffer length
341 count - number of bytes removed (encoded) from source buffer
342 dst _ destination buffer
343 dsize - destination buffer size
344 returns - number of encoded bytes in the destination buffer
346 int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
347 unsigned short slen, int *count,
348 unsigned char *dst, int dsize)
350 static const unsigned char xfast_flag_value[] = {
351 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
359 if(hdlc->bit_shift==0){
360 if(slen && !hdlc->do_closing){
361 hdlc->shift_reg = *src++;
364 hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
367 if(hdlc->state == HDLC_SEND_DATA){
368 if(hdlc->data_received){
369 hdlc->state = HDLC_SEND_CRC1;
372 hdlc->shift_reg = hdlc->crc & 0xff;
373 } else if(!hdlc->do_adapt56){
374 hdlc->state = HDLC_SEND_FAST_FLAG;
376 hdlc->state = HDLC_SENDFLAG_B0;
389 case HDLC_SEND_FAST_FLAG:
390 hdlc->do_closing = 0;
392 *dst++ = hdlc->ffvalue;
397 if(hdlc->bit_shift==8){
398 hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
399 hdlc->state = HDLC_SEND_DATA;
401 hdlc->hdlc_bits1 = 0;
402 hdlc->data_received = 1;
405 case HDLC_SENDFLAG_B0:
406 hdlc->do_closing = 0;
409 hdlc->hdlc_bits1 = 0;
410 hdlc->state = HDLC_SENDFLAG_B1A6;
412 case HDLC_SENDFLAG_B1A6:
416 if(++hdlc->hdlc_bits1 == 6)
417 hdlc->state = HDLC_SENDFLAG_B7;
419 case HDLC_SENDFLAG_B7:
423 hdlc->state = HDLC_SENDFLAG_B0;
426 if(hdlc->bit_shift==8){
427 hdlc->state = HDLC_SEND_DATA;
429 hdlc->hdlc_bits1 = 0;
430 hdlc->data_received = 1;
433 case HDLC_SEND_FIRST_FLAG:
434 hdlc->data_received = 1;
435 if(hdlc->data_bits==8){
436 hdlc->state = HDLC_SEND_DATA;
438 hdlc->hdlc_bits1 = 0;
443 if(hdlc->shift_reg & 0x01)
445 hdlc->shift_reg >>= 1;
447 if(hdlc->bit_shift==0){
448 hdlc->state = HDLC_SEND_DATA;
450 hdlc->hdlc_bits1 = 0;
456 if(hdlc->hdlc_bits1 == 5){
457 hdlc->hdlc_bits1 = 0;
460 if(hdlc->bit_shift==8){
461 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
463 if(hdlc->shift_reg & 0x01){
466 hdlc->shift_reg >>= 1;
469 hdlc->hdlc_bits1 = 0;
470 hdlc->shift_reg >>= 1;
477 if(hdlc->hdlc_bits1 == 5){
478 hdlc->hdlc_bits1 = 0;
481 if(hdlc->shift_reg & 0x01){
484 hdlc->shift_reg >>= 1;
487 hdlc->hdlc_bits1 = 0;
488 hdlc->shift_reg >>= 1;
491 if(hdlc->bit_shift==0){
492 hdlc->shift_reg = (hdlc->crc >> 8);
493 hdlc->state = HDLC_SEND_CRC2;
500 if(hdlc->hdlc_bits1 == 5){
501 hdlc->hdlc_bits1 = 0;
504 if(hdlc->shift_reg & 0x01){
507 hdlc->shift_reg >>= 1;
510 hdlc->hdlc_bits1 = 0;
511 hdlc->shift_reg >>= 1;
514 if(hdlc->bit_shift==0){
515 hdlc->shift_reg = 0x7e;
516 hdlc->state = HDLC_SEND_CLOSING_FLAG;
520 case HDLC_SEND_CLOSING_FLAG:
523 if(hdlc->hdlc_bits1 == 5){
524 hdlc->hdlc_bits1 = 0;
527 if(hdlc->shift_reg & 0x01){
530 hdlc->shift_reg >>= 1;
532 if(hdlc->bit_shift==0){
533 hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
535 hdlc->ffvalue = 0x7e;
536 hdlc->state = HDLC_SEND_IDLE1;
537 hdlc->bit_shift = 8-hdlc->data_bits;
538 if(hdlc->bit_shift==0)
539 hdlc->state = HDLC_SEND_FAST_IDLE;
541 if(!hdlc->do_adapt56){
542 hdlc->state = HDLC_SEND_FAST_FLAG;
543 hdlc->data_received = 0;
545 hdlc->state = HDLC_SENDFLAG_B0;
546 hdlc->data_received = 0;
548 // Finished with this frame, send flags
549 if (dsize > 1) dsize = 1;
553 case HDLC_SEND_IDLE1:
554 hdlc->do_closing = 0;
559 if(hdlc->bit_shift==0){
560 hdlc->state = HDLC_SEND_FAST_IDLE;
564 case HDLC_SEND_FAST_IDLE:
565 hdlc->do_closing = 0;
568 if(hdlc->bit_shift == 8){
570 hdlc->state = HDLC_SEND_FIRST_FLAG;
573 hdlc->bit_shift = hdlc->data_bits = 0;
581 if(hdlc->do_adapt56){
582 if(hdlc->data_bits==7){
588 if(hdlc->data_bits==8){
600 EXPORT_SYMBOL(isdnhdlc_rcv_init);
601 EXPORT_SYMBOL(isdnhdlc_decode);
602 EXPORT_SYMBOL(isdnhdlc_out_init);
603 EXPORT_SYMBOL(isdnhdlc_encode);