• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
3  *
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>
7  *
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.
12  *
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.
17  *
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.
21  */
22 
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/crc-ccitt.h>
26 #include "isdnhdlc.h"
27 
28 /*-------------------------------------------------------------------*/
29 
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");
35 
36 /*-------------------------------------------------------------------*/
37 
38 enum {
39 	HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
40 	HDLC_GET_DATA,HDLC_FAST_FLAG
41 };
42 
43 enum {
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
48 };
49 
isdnhdlc_rcv_init(struct isdnhdlc_vars * hdlc,int do_adapt56)50 void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
51 {
52    	hdlc->bit_shift = 0;
53 	hdlc->hdlc_bits1 = 0;
54 	hdlc->data_bits = 0;
55 	hdlc->ffbit_shift = 0;
56 	hdlc->data_received = 0;
57 	hdlc->state = HDLC_GET_DATA;
58 	hdlc->do_adapt56 = do_adapt56;
59 	hdlc->dchannel = 0;
60 	hdlc->crc = 0;
61 	hdlc->cbin = 0;
62 	hdlc->shift_reg = 0;
63 	hdlc->ffvalue = 0;
64 	hdlc->dstpos = 0;
65 }
66 
isdnhdlc_out_init(struct isdnhdlc_vars * hdlc,int is_d_channel,int do_adapt56)67 void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
68 {
69    	hdlc->bit_shift = 0;
70 	hdlc->hdlc_bits1 = 0;
71 	hdlc->data_bits = 0;
72 	hdlc->ffbit_shift = 0;
73 	hdlc->data_received = 0;
74 	hdlc->do_closing = 0;
75 	hdlc->ffvalue = 0;
76 	if (is_d_channel) {
77 		hdlc->dchannel = 1;
78 		hdlc->state = HDLC_SEND_FIRST_FLAG;
79 	} else {
80 		hdlc->dchannel = 0;
81 		hdlc->state = HDLC_SEND_FAST_FLAG;
82 		hdlc->ffvalue = 0x7e;
83 	}
84 	hdlc->cbin = 0x7e;
85 	hdlc->bit_shift = 0;
86 	if(do_adapt56){
87 		hdlc->do_adapt56 = 1;
88 		hdlc->data_bits = 0;
89 		hdlc->state = HDLC_SENDFLAG_B0;
90 	} else {
91 		hdlc->do_adapt56 = 0;
92 		hdlc->data_bits = 8;
93 	}
94 	hdlc->shift_reg = 0;
95 }
96 
97 /*
98   isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
99 
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
108   the length.
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.
115 
116   src - source buffer
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
122   flag.
123  */
isdnhdlc_decode(struct isdnhdlc_vars * hdlc,const unsigned char * src,int slen,int * count,unsigned char * dst,int dsize)124 int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
125 		     int slen, int *count, unsigned char *dst, int dsize)
126 {
127 	int status=0;
128 
129 	static const unsigned char fast_flag[]={
130 		0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
131 	};
132 
133 	static const unsigned char fast_flag_value[]={
134 		0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
135 	};
136 
137 	static const unsigned char fast_abort[]={
138 		0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
139 	};
140 
141 	*count = slen;
142 
143 	while(slen > 0){
144 		if(hdlc->bit_shift==0){
145 			hdlc->cbin = *src++;
146 			slen--;
147 			hdlc->bit_shift = 8;
148 			if(hdlc->do_adapt56){
149 				hdlc->bit_shift --;
150 			}
151 		}
152 
153 		switch(hdlc->state){
154 		case STOPPED:
155 			return 0;
156 		case HDLC_FAST_IDLE:
157 			if(hdlc->cbin == 0xff){
158 				hdlc->bit_shift = 0;
159 				break;
160 			}
161 			hdlc->state = HDLC_GET_FLAG_B0;
162 			hdlc->hdlc_bits1 = 0;
163 			hdlc->bit_shift = 8;
164 			break;
165 		case HDLC_GET_FLAG_B0:
166 			if(!(hdlc->cbin & 0x80)) {
167 				hdlc->state = HDLC_GETFLAG_B1A6;
168 				hdlc->hdlc_bits1 = 0;
169 			} else {
170 				if(!hdlc->do_adapt56){
171 					if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
172 						hdlc->state = HDLC_FAST_IDLE;
173 				}
174 			}
175 			hdlc->cbin<<=1;
176 			hdlc->bit_shift --;
177 			break;
178 		case HDLC_GETFLAG_B1A6:
179 			if(hdlc->cbin & 0x80){
180 				hdlc->hdlc_bits1++;
181 				if(hdlc->hdlc_bits1==6){
182 					hdlc->state = HDLC_GETFLAG_B7;
183 				}
184 			} else {
185 				hdlc->hdlc_bits1 = 0;
186 			}
187 			hdlc->cbin<<=1;
188 			hdlc->bit_shift --;
189 			break;
190 		case HDLC_GETFLAG_B7:
191 			if(hdlc->cbin & 0x80) {
192 				hdlc->state = HDLC_GET_FLAG_B0;
193 			} else {
194 				hdlc->state = HDLC_GET_DATA;
195 				hdlc->crc = 0xffff;
196 				hdlc->shift_reg = 0;
197 				hdlc->hdlc_bits1 = 0;
198 				hdlc->data_bits = 0;
199 				hdlc->data_received = 0;
200 			}
201 			hdlc->cbin<<=1;
202 			hdlc->bit_shift --;
203 			break;
204 		case HDLC_GET_DATA:
205 			if(hdlc->cbin & 0x80){
206 				hdlc->hdlc_bits1++;
207 				switch(hdlc->hdlc_bits1){
208 				case 6:
209 					break;
210 				case 7:
211 					if(hdlc->data_received) {
212 						// bad frame
213 						status = -HDLC_FRAMING_ERROR;
214 					}
215 					if(!hdlc->do_adapt56){
216 						if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
217 							hdlc->state = HDLC_FAST_IDLE;
218 							hdlc->bit_shift=1;
219 							break;
220 						}
221 					} else {
222 						hdlc->state = HDLC_GET_FLAG_B0;
223 					}
224 					break;
225 				default:
226 					hdlc->shift_reg>>=1;
227 					hdlc->shift_reg |= 0x80;
228 					hdlc->data_bits++;
229 					break;
230 				}
231 			} else {
232 				switch(hdlc->hdlc_bits1){
233 				case 5:
234 					break;
235 				case 6:
236 					if(hdlc->data_received){
237 						if (hdlc->dstpos < 2) {
238 							status = -HDLC_FRAMING_ERROR;
239 						} else if (hdlc->crc != 0xf0b8){
240 							// crc error
241 							status = -HDLC_CRC_ERROR;
242 						} else {
243 							// remove CRC
244 							hdlc->dstpos -= 2;
245 							// good frame
246 							status = hdlc->dstpos;
247 						}
248 					}
249 					hdlc->crc = 0xffff;
250 					hdlc->shift_reg = 0;
251 					hdlc->data_bits = 0;
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;
257 							hdlc->bit_shift = 1;
258 						} else {
259 							hdlc->state = HDLC_GET_DATA;
260 							hdlc->data_received = 0;
261 						}
262 					} else {
263 						hdlc->state = HDLC_GET_DATA;
264 						hdlc->data_received = 0;
265 					}
266 					break;
267 				default:
268 					hdlc->shift_reg>>=1;
269 					hdlc->data_bits++;
270 					break;
271 				}
272 				hdlc->hdlc_bits1 = 0;
273 			}
274 			if (status) {
275 				hdlc->dstpos = 0;
276 				*count -= slen;
277 				hdlc->cbin <<= 1;
278 				hdlc->bit_shift--;
279 				return status;
280 			}
281 			if(hdlc->data_bits==8){
282 				hdlc->data_bits = 0;
283 				hdlc->data_received = 1;
284 				hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
285 
286 				// good byte received
287 				if (hdlc->dstpos < dsize) {
288 					dst[hdlc->dstpos++] = hdlc->shift_reg;
289 				} else {
290 					// frame too long
291 					status = -HDLC_LENGTH_ERROR;
292 					hdlc->dstpos = 0;
293 				}
294 			}
295 			hdlc->cbin <<= 1;
296 			hdlc->bit_shift--;
297 			break;
298 		case HDLC_FAST_FLAG:
299 			if(hdlc->cbin==hdlc->ffvalue){
300 				hdlc->bit_shift = 0;
301 				break;
302 			} else {
303 				if(hdlc->cbin == 0xff){
304 					hdlc->state = HDLC_FAST_IDLE;
305 					hdlc->bit_shift=0;
306 				} else if(hdlc->ffbit_shift==8){
307 					hdlc->state = HDLC_GETFLAG_B7;
308 					break;
309 				} else {
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;
316 				}
317 			}
318 			break;
319 		default:
320 			break;
321 		}
322 	}
323 	*count -= slen;
324 	return 0;
325 }
326 
327 /*
328   isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
329 
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
332   (0 after 5 1's).
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.
338 
339   src - source buffer
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
345 */
isdnhdlc_encode(struct isdnhdlc_vars * hdlc,const unsigned char * src,unsigned short slen,int * count,unsigned char * dst,int dsize)346 int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
347 		unsigned short slen, int *count,
348 		unsigned char *dst, int dsize)
349 {
350 	static const unsigned char xfast_flag_value[] = {
351 		0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
352 	};
353 
354 	int len = 0;
355 
356 	*count = slen;
357 
358 	while (dsize > 0) {
359 		if(hdlc->bit_shift==0){
360 			if(slen && !hdlc->do_closing){
361 				hdlc->shift_reg = *src++;
362 				slen--;
363 				if (slen == 0)
364 					hdlc->do_closing = 1;  /* closing sequence, CRC + flag(s) */
365 				hdlc->bit_shift = 8;
366 			} else {
367 				if(hdlc->state == HDLC_SEND_DATA){
368 					if(hdlc->data_received){
369 						hdlc->state = HDLC_SEND_CRC1;
370 						hdlc->crc ^= 0xffff;
371 						hdlc->bit_shift = 8;
372 						hdlc->shift_reg = hdlc->crc & 0xff;
373 					} else if(!hdlc->do_adapt56){
374 						hdlc->state = HDLC_SEND_FAST_FLAG;
375 					} else {
376 						hdlc->state = HDLC_SENDFLAG_B0;
377 					}
378 				}
379 
380 			}
381 		}
382 
383 		switch(hdlc->state){
384 		case STOPPED:
385 			while (dsize--)
386 				*dst++ = 0xff;
387 
388 			return dsize;
389 		case HDLC_SEND_FAST_FLAG:
390 			hdlc->do_closing = 0;
391 			if(slen == 0){
392 				*dst++ = hdlc->ffvalue;
393 				len++;
394 				dsize--;
395 				break;
396 			}
397 			if(hdlc->bit_shift==8){
398 				hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
399 				hdlc->state = HDLC_SEND_DATA;
400 				hdlc->crc = 0xffff;
401 				hdlc->hdlc_bits1 = 0;
402 				hdlc->data_received = 1;
403 			}
404 			break;
405 		case HDLC_SENDFLAG_B0:
406 			hdlc->do_closing = 0;
407 			hdlc->cbin <<= 1;
408 			hdlc->data_bits++;
409 			hdlc->hdlc_bits1 = 0;
410 			hdlc->state = HDLC_SENDFLAG_B1A6;
411 			break;
412 		case HDLC_SENDFLAG_B1A6:
413 			hdlc->cbin <<= 1;
414 			hdlc->data_bits++;
415 			hdlc->cbin++;
416 			if(++hdlc->hdlc_bits1 == 6)
417 				hdlc->state = HDLC_SENDFLAG_B7;
418 			break;
419 		case HDLC_SENDFLAG_B7:
420 			hdlc->cbin <<= 1;
421 			hdlc->data_bits++;
422 			if(slen == 0){
423 				hdlc->state = HDLC_SENDFLAG_B0;
424 				break;
425 			}
426 			if(hdlc->bit_shift==8){
427 				hdlc->state = HDLC_SEND_DATA;
428 				hdlc->crc = 0xffff;
429 				hdlc->hdlc_bits1 = 0;
430 				hdlc->data_received = 1;
431 			}
432 			break;
433 		case HDLC_SEND_FIRST_FLAG:
434 			hdlc->data_received = 1;
435 			if(hdlc->data_bits==8){
436 				hdlc->state = HDLC_SEND_DATA;
437 				hdlc->crc = 0xffff;
438 				hdlc->hdlc_bits1 = 0;
439 				break;
440 			}
441 			hdlc->cbin <<= 1;
442 			hdlc->data_bits++;
443 			if(hdlc->shift_reg & 0x01)
444 				hdlc->cbin++;
445 			hdlc->shift_reg >>= 1;
446 			hdlc->bit_shift--;
447 			if(hdlc->bit_shift==0){
448 				hdlc->state = HDLC_SEND_DATA;
449 				hdlc->crc = 0xffff;
450 				hdlc->hdlc_bits1 = 0;
451 			}
452 			break;
453 		case HDLC_SEND_DATA:
454 			hdlc->cbin <<= 1;
455 			hdlc->data_bits++;
456 			if(hdlc->hdlc_bits1 == 5){
457 				hdlc->hdlc_bits1 = 0;
458 				break;
459 			}
460 			if(hdlc->bit_shift==8){
461 				hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
462 			}
463 			if(hdlc->shift_reg & 0x01){
464 				hdlc->hdlc_bits1++;
465 				hdlc->cbin++;
466 				hdlc->shift_reg >>= 1;
467 				hdlc->bit_shift--;
468 			} else {
469 				hdlc->hdlc_bits1 = 0;
470 				hdlc->shift_reg >>= 1;
471 				hdlc->bit_shift--;
472 			}
473 			break;
474 		case HDLC_SEND_CRC1:
475 			hdlc->cbin <<= 1;
476 			hdlc->data_bits++;
477 			if(hdlc->hdlc_bits1 == 5){
478 				hdlc->hdlc_bits1 = 0;
479 				break;
480 			}
481 			if(hdlc->shift_reg & 0x01){
482 				hdlc->hdlc_bits1++;
483 				hdlc->cbin++;
484 				hdlc->shift_reg >>= 1;
485 				hdlc->bit_shift--;
486 			} else {
487 				hdlc->hdlc_bits1 = 0;
488 				hdlc->shift_reg >>= 1;
489 				hdlc->bit_shift--;
490 			}
491 			if(hdlc->bit_shift==0){
492 				hdlc->shift_reg = (hdlc->crc >> 8);
493 				hdlc->state = HDLC_SEND_CRC2;
494 				hdlc->bit_shift = 8;
495 			}
496 			break;
497 		case HDLC_SEND_CRC2:
498 			hdlc->cbin <<= 1;
499 			hdlc->data_bits++;
500 			if(hdlc->hdlc_bits1 == 5){
501 				hdlc->hdlc_bits1 = 0;
502 				break;
503 			}
504 			if(hdlc->shift_reg & 0x01){
505 				hdlc->hdlc_bits1++;
506 				hdlc->cbin++;
507 				hdlc->shift_reg >>= 1;
508 				hdlc->bit_shift--;
509 			} else {
510 				hdlc->hdlc_bits1 = 0;
511 				hdlc->shift_reg >>= 1;
512 				hdlc->bit_shift--;
513 			}
514 			if(hdlc->bit_shift==0){
515 				hdlc->shift_reg = 0x7e;
516 				hdlc->state = HDLC_SEND_CLOSING_FLAG;
517 				hdlc->bit_shift = 8;
518 			}
519 			break;
520 		case HDLC_SEND_CLOSING_FLAG:
521 			hdlc->cbin <<= 1;
522 			hdlc->data_bits++;
523 			if(hdlc->hdlc_bits1 == 5){
524 				hdlc->hdlc_bits1 = 0;
525 				break;
526 			}
527 			if(hdlc->shift_reg & 0x01){
528 				hdlc->cbin++;
529 			}
530 			hdlc->shift_reg >>= 1;
531 			hdlc->bit_shift--;
532 			if(hdlc->bit_shift==0){
533 				hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
534 				if(hdlc->dchannel){
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;
540 				} else {
541 					if(!hdlc->do_adapt56){
542 						hdlc->state = HDLC_SEND_FAST_FLAG;
543 						hdlc->data_received = 0;
544 					} else {
545 						hdlc->state = HDLC_SENDFLAG_B0;
546 						hdlc->data_received = 0;
547 					}
548 					// Finished with this frame, send flags
549 					if (dsize > 1) dsize = 1;
550 				}
551 			}
552 			break;
553 		case HDLC_SEND_IDLE1:
554 			hdlc->do_closing = 0;
555 			hdlc->cbin <<= 1;
556 			hdlc->cbin++;
557 			hdlc->data_bits++;
558 			hdlc->bit_shift--;
559 			if(hdlc->bit_shift==0){
560 				hdlc->state = HDLC_SEND_FAST_IDLE;
561 				hdlc->bit_shift = 0;
562 			}
563 			break;
564 		case HDLC_SEND_FAST_IDLE:
565 			hdlc->do_closing = 0;
566 			hdlc->cbin = 0xff;
567 			hdlc->data_bits = 8;
568 			if(hdlc->bit_shift == 8){
569 				hdlc->cbin = 0x7e;
570 				hdlc->state = HDLC_SEND_FIRST_FLAG;
571 			} else {
572 				*dst++ = hdlc->cbin;
573 				hdlc->bit_shift = hdlc->data_bits = 0;
574 				len++;
575 				dsize = 0;
576 			}
577 			break;
578 		default:
579 			break;
580 		}
581 		if(hdlc->do_adapt56){
582 			if(hdlc->data_bits==7){
583 				hdlc->cbin <<= 1;
584 				hdlc->cbin++;
585 				hdlc->data_bits++;
586 			}
587 		}
588 		if(hdlc->data_bits==8){
589 			*dst++ = hdlc->cbin;
590 			hdlc->data_bits = 0;
591 			len++;
592 			dsize--;
593 		}
594 	}
595 	*count -= slen;
596 
597 	return len;
598 }
599 
600 EXPORT_SYMBOL(isdnhdlc_rcv_init);
601 EXPORT_SYMBOL(isdnhdlc_decode);
602 EXPORT_SYMBOL(isdnhdlc_out_init);
603 EXPORT_SYMBOL(isdnhdlc_encode);
604