/* isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. The source buffer is scanned for valid HDLC frames looking for flags (01111110) to indicate the start of a frame. If the start of the frame is found, the bit stuffing is removed (0 after 5 1's). When a new flag is found, the complete frame has been received and the CRC is checked. If a valid frame is found, the function returns the frame length excluding the CRC with the bit HDLC_END_OF_FRAME set. If the beginning of a valid frame is found, the function returns the length. If a framing error is found (too many 1s and not a flag) the function returns the length with the bit HDLC_FRAMING_ERROR set. If a CRC error is found the function returns the length with the bit HDLC_CRC_ERROR set. If the frame length exceeds the destination buffer size, the function returns the length with the bit HDLC_LENGTH_ERROR set. src - source buffer slen - source buffer length count - number of bytes removed (decoded) from the source buffer dst _ destination buffer dsize - destination buffer size returns - number of decoded bytes in the destination buffer and status flag. */ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen, int *count, unsigned char *dst, int dsize) { int status=0; static const unsigned char fast_flag[]={ 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f }; static const unsigned char fast_flag_value[]={ 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f }; static const unsigned char fast_abort[]={ 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; *count = slen; while(slen > 0){ if(hdlc->bit_shift==0){ hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; if(hdlc->do_adapt56){ hdlc->bit_shift --; } } switch(hdlc->state){ case STOPPED: return 0; case HDLC_FAST_IDLE: if(hdlc->cbin == 0xff){ hdlc->bit_shift = 0; break; } hdlc->state = HDLC_GET_FLAG_B0; hdlc->hdlc_bits1 = 0; hdlc->bit_shift = 8; break; case HDLC_GET_FLAG_B0: if(!(hdlc->cbin & 0x80)) { hdlc->state = HDLC_GETFLAG_B1A6; hdlc->hdlc_bits1 = 0; } else { if(!hdlc->do_adapt56){ if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) hdlc->state = HDLC_FAST_IDLE; } } hdlc->cbin<<=1; hdlc->bit_shift --; break; case HDLC_GETFLAG_B1A6: if(hdlc->cbin & 0x80){ hdlc->hdlc_bits1++; if(hdlc->hdlc_bits1==6){ hdlc->state = HDLC_GETFLAG_B7; } } else { hdlc->hdlc_bits1 = 0; } hdlc->cbin<<=1; hdlc->bit_shift --; break; case HDLC_GETFLAG_B7: if(hdlc->cbin & 0x80) { hdlc->state = HDLC_GET_FLAG_B0; } else { hdlc->state = HDLC_GET_DATA; hdlc->crc = 0xffff; hdlc->shift_reg = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->data_received = 0; } hdlc->cbin<<=1; hdlc->bit_shift --; break; case HDLC_GET_DATA: if(hdlc->cbin & 0x80){ hdlc->hdlc_bits1++; switch(hdlc->hdlc_bits1){ case 6: break; case 7: if(hdlc->data_received) { // bad frame status = -HDLC_FRAMING_ERROR; } if(!hdlc->do_adapt56){ if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ hdlc->state = HDLC_FAST_IDLE; hdlc->bit_shift=1; break; } } else { hdlc->state = HDLC_GET_FLAG_B0; } break; default: hdlc->shift_reg>>=1; hdlc->shift_reg |= 0x80; hdlc->data_bits++; break; } } else { switch(hdlc->hdlc_bits1){ case 5: break; case 6: if(hdlc->data_received){ if (hdlc->dstpos < 2) { status = -HDLC_FRAMING_ERROR; } else if (hdlc->crc != 0xf0b8){ // crc error status = -HDLC_CRC_ERROR; } else { // remove CRC hdlc->dstpos -= 2; // good frame status = hdlc->dstpos; } } hdlc->crc = 0xffff; hdlc->shift_reg = 0; hdlc->data_bits = 0; if(!hdlc->do_adapt56){ if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; hdlc->state = HDLC_FAST_FLAG; hdlc->ffbit_shift = hdlc->bit_shift; hdlc->bit_shift = 1; } else { hdlc->state = HDLC_GET_DATA; hdlc->data_received = 0; } } else { hdlc->state = HDLC_GET_DATA; hdlc->data_received = 0; } break; default: hdlc->shift_reg>>=1; hdlc->data_bits++; break; } hdlc->hdlc_bits1 = 0; } if (status) { hdlc->dstpos = 0; *count -= slen; hdlc->cbin <<= 1; hdlc->bit_shift--; return status; } if(hdlc->data_bits==8){ hdlc->data_bits = 0; hdlc->data_received = 1; hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); // good byte received if (dsize--) { dst[hdlc->dstpos++] = hdlc->shift_reg; } else { // frame too long status = -HDLC_LENGTH_ERROR; hdlc->dstpos = 0; } } hdlc->cbin <<= 1; hdlc->bit_shift--; break; case HDLC_FAST_FLAG: if(hdlc->cbin==hdlc->ffvalue){ hdlc->bit_shift = 0; break; } else { if(hdlc->cbin == 0xff){ hdlc->state = HDLC_FAST_IDLE; hdlc->bit_shift=0; } else if(hdlc->ffbit_shift==8){ hdlc->state = HDLC_GETFLAG_B7; break; } else { hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; hdlc->data_bits = hdlc->ffbit_shift-1; hdlc->state = HDLC_GET_DATA; hdlc->data_received = 0; } } break; default: break; }
/* isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. The source buffer is scanned for valid HDLC frames looking for flags (01111110) to indicate the start of a frame. If the start of the frame is found, the bit stuffing is removed (0 after 5 1's). When a new flag is found, the complete frame has been received and the CRC is checked. If a valid frame is found, the function returns the frame length excluding the CRC with the bit HDLC_END_OF_FRAME set. If the beginning of a valid frame is found, the function returns the length. If a framing error is found (too many 1s and not a flag) the function returns the length with the bit HDLC_FRAMING_ERROR set. If a CRC error is found the function returns the length with the bit HDLC_CRC_ERROR set. If the frame length exceeds the destination buffer size, the function returns the length with the bit HDLC_LENGTH_ERROR set. src - source buffer slen - source buffer length count - number of bytes removed (decoded) from the source buffer dst _ destination buffer dsize - destination buffer size returns - number of decoded bytes in the destination buffer and status flag. */ int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, int *count, u8 *dst, int dsize) { int status = 0; static const unsigned char fast_flag[] = { 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f }; static const unsigned char fast_flag_value[] = { 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f }; static const unsigned char fast_abort[] = { 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; #define handle_fast_flag(h) \ do { \ if (h->cbin == fast_flag[h->bit_shift]) { \ h->ffvalue = fast_flag_value[h->bit_shift]; \ h->state = HDLC_FAST_FLAG; \ h->ffbit_shift = h->bit_shift; \ h->bit_shift = 1; \ } else { \ h->state = HDLC_GET_DATA; \ h->data_received = 0; \ } \ } while (0) #define handle_abort(h) \ do { \ h->shift_reg = fast_abort[h->ffbit_shift - 1]; \ h->hdlc_bits1 = h->ffbit_shift - 2; \ if (h->hdlc_bits1 < 0) \ h->hdlc_bits1 = 0; \ h->data_bits = h->ffbit_shift - 1; \ h->state = HDLC_GET_DATA; \ h->data_received = 0; \ } while (0) *count = slen; while (slen > 0) { if (hdlc->bit_shift == 0) { /* the code is for bitreverse streams */ if (hdlc->do_bitreverse == 0) hdlc->cbin = bitrev8(*src++); else hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; if (hdlc->do_adapt56) hdlc->bit_shift--; } switch (hdlc->state) { case STOPPED: return 0; case HDLC_FAST_IDLE: if (hdlc->cbin == 0xff) { hdlc->bit_shift = 0; break; } hdlc->state = HDLC_GET_FLAG_B0; hdlc->hdlc_bits1 = 0; hdlc->bit_shift = 8; break; case HDLC_GET_FLAG_B0: if (!(hdlc->cbin & 0x80)) { hdlc->state = HDLC_GETFLAG_B1A6; hdlc->hdlc_bits1 = 0; } else { if ((!hdlc->do_adapt56) && (++hdlc->hdlc_bits1 >= 8) && (hdlc->bit_shift == 1)) hdlc->state = HDLC_FAST_IDLE; } hdlc->cbin <<= 1; hdlc->bit_shift--; break; case HDLC_GETFLAG_B1A6: if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; if (hdlc->hdlc_bits1 == 6) hdlc->state = HDLC_GETFLAG_B7; } else hdlc->hdlc_bits1 = 0; hdlc->cbin <<= 1; hdlc->bit_shift--; break; case HDLC_GETFLAG_B7: if (hdlc->cbin & 0x80) { hdlc->state = HDLC_GET_FLAG_B0; } else { hdlc->state = HDLC_GET_DATA; hdlc->crc = 0xffff; hdlc->shift_reg = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->data_received = 0; } hdlc->cbin <<= 1; hdlc->bit_shift--; break; case HDLC_GET_DATA: if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; switch (hdlc->hdlc_bits1) { case 6: break; case 7: if (hdlc->data_received) /* bad frame */ status = -HDLC_FRAMING_ERROR; if (!hdlc->do_adapt56) { if (hdlc->cbin == fast_abort [hdlc->bit_shift + 1]) { hdlc->state = HDLC_FAST_IDLE; hdlc->bit_shift = 1; break; } } else hdlc->state = HDLC_GET_FLAG_B0; break; default: hdlc->shift_reg >>= 1; hdlc->shift_reg |= 0x80; hdlc->data_bits++; break; } } else { switch (hdlc->hdlc_bits1) { case 5: break; case 6: if (hdlc->data_received) status = check_frame(hdlc); hdlc->crc = 0xffff; hdlc->shift_reg = 0; hdlc->data_bits = 0; if (!hdlc->do_adapt56) handle_fast_flag(hdlc); else { hdlc->state = HDLC_GET_DATA; hdlc->data_received = 0; } break; default: hdlc->shift_reg >>= 1; hdlc->data_bits++; break; } hdlc->hdlc_bits1 = 0; } if (status) { hdlc->dstpos = 0; *count -= slen; hdlc->cbin <<= 1; hdlc->bit_shift--; return status; } if (hdlc->data_bits == 8) { hdlc->data_bits = 0; hdlc->data_received = 1; hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); /* good byte received */ if (hdlc->dstpos < dsize) dst[hdlc->dstpos++] = hdlc->shift_reg; else { /* frame too long */ status = -HDLC_LENGTH_ERROR; hdlc->dstpos = 0; } } hdlc->cbin <<= 1; hdlc->bit_shift--; break; case HDLC_FAST_FLAG: if (hdlc->cbin == hdlc->ffvalue) { hdlc->bit_shift = 0; break; } else { if (hdlc->cbin == 0xff) { hdlc->state = HDLC_FAST_IDLE; hdlc->bit_shift = 0; } else if (hdlc->ffbit_shift == 8) { hdlc->state = HDLC_GETFLAG_B7; break; } else handle_abort(hdlc); } break; default: break; }
/** * crc_ccitt - recompute the CRC for the data buffer * @crc: previous CRC value * @buffer: data pointer * @len: number of bytes in the buffer */ quint16 crc_ccitt(quint16 crc, uchar const *buffer, size_t len) { while (len--) crc = crc_ccitt_byte(crc, *buffer++); return crc; }
/** * crc_ccitt - recompute the CRC for the data buffer * @crc - previous CRC value * @buffer - data pointer * @len - number of bytes in the buffer */ u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len) { while (len--) crc = crc_ccitt_byte(crc, *buffer++); return crc; }