/*
  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;
		}
Esempio n. 2
0
/*
  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;
		}
Esempio n. 3
0
/**
 *	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;
}
Esempio n. 4
0
/**
 *	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;
}