Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/i4l/isdnhdlc.c
15111 views
1
/*
2
* isdnhdlc.c -- General purpose ISDN HDLC decoder.
3
*
4
* Copyright (C)
5
* 2009 Karsten Keil <[email protected]>
6
* 2002 Wolfgang Mües <[email protected]>
7
* 2001 Frode Isaksen <[email protected]>
8
* 2001 Kai Germaschewski <[email protected]>
9
*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
14
*
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
19
*
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
*/
24
25
#include <linux/module.h>
26
#include <linux/init.h>
27
#include <linux/crc-ccitt.h>
28
#include <linux/isdn/hdlc.h>
29
#include <linux/bitrev.h>
30
31
/*-------------------------------------------------------------------*/
32
33
MODULE_AUTHOR("Wolfgang Mües <[email protected]>, "
34
"Frode Isaksen <[email protected]>, "
35
"Kai Germaschewski <[email protected]>");
36
MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
37
MODULE_LICENSE("GPL");
38
39
/*-------------------------------------------------------------------*/
40
41
enum {
42
HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
43
HDLC_GET_DATA, HDLC_FAST_FLAG
44
};
45
46
enum {
47
HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
48
HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
49
HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
50
HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
51
};
52
53
void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
54
{
55
memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
56
hdlc->state = HDLC_GET_DATA;
57
if (features & HDLC_56KBIT)
58
hdlc->do_adapt56 = 1;
59
if (features & HDLC_BITREVERSE)
60
hdlc->do_bitreverse = 1;
61
}
62
EXPORT_SYMBOL(isdnhdlc_out_init);
63
64
void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
65
{
66
memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
67
if (features & HDLC_DCHANNEL) {
68
hdlc->dchannel = 1;
69
hdlc->state = HDLC_SEND_FIRST_FLAG;
70
} else {
71
hdlc->dchannel = 0;
72
hdlc->state = HDLC_SEND_FAST_FLAG;
73
hdlc->ffvalue = 0x7e;
74
}
75
hdlc->cbin = 0x7e;
76
if (features & HDLC_56KBIT) {
77
hdlc->do_adapt56 = 1;
78
hdlc->state = HDLC_SENDFLAG_B0;
79
} else
80
hdlc->data_bits = 8;
81
if (features & HDLC_BITREVERSE)
82
hdlc->do_bitreverse = 1;
83
}
84
EXPORT_SYMBOL(isdnhdlc_rcv_init);
85
86
static int
87
check_frame(struct isdnhdlc_vars *hdlc)
88
{
89
int status;
90
91
if (hdlc->dstpos < 2) /* too small - framing error */
92
status = -HDLC_FRAMING_ERROR;
93
else if (hdlc->crc != 0xf0b8) /* crc error */
94
status = -HDLC_CRC_ERROR;
95
else {
96
/* remove CRC */
97
hdlc->dstpos -= 2;
98
/* good frame */
99
status = hdlc->dstpos;
100
}
101
return status;
102
}
103
104
/*
105
isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
106
107
The source buffer is scanned for valid HDLC frames looking for
108
flags (01111110) to indicate the start of a frame. If the start of
109
the frame is found, the bit stuffing is removed (0 after 5 1's).
110
When a new flag is found, the complete frame has been received
111
and the CRC is checked.
112
If a valid frame is found, the function returns the frame length
113
excluding the CRC with the bit HDLC_END_OF_FRAME set.
114
If the beginning of a valid frame is found, the function returns
115
the length.
116
If a framing error is found (too many 1s and not a flag) the function
117
returns the length with the bit HDLC_FRAMING_ERROR set.
118
If a CRC error is found the function returns the length with the
119
bit HDLC_CRC_ERROR set.
120
If the frame length exceeds the destination buffer size, the function
121
returns the length with the bit HDLC_LENGTH_ERROR set.
122
123
src - source buffer
124
slen - source buffer length
125
count - number of bytes removed (decoded) from the source buffer
126
dst _ destination buffer
127
dsize - destination buffer size
128
returns - number of decoded bytes in the destination buffer and status
129
flag.
130
*/
131
int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
132
int *count, u8 *dst, int dsize)
133
{
134
int status = 0;
135
136
static const unsigned char fast_flag[] = {
137
0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
138
};
139
140
static const unsigned char fast_flag_value[] = {
141
0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
142
};
143
144
static const unsigned char fast_abort[] = {
145
0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
146
};
147
148
#define handle_fast_flag(h) \
149
do {\
150
if (h->cbin == fast_flag[h->bit_shift]) {\
151
h->ffvalue = fast_flag_value[h->bit_shift];\
152
h->state = HDLC_FAST_FLAG;\
153
h->ffbit_shift = h->bit_shift;\
154
h->bit_shift = 1;\
155
} else {\
156
h->state = HDLC_GET_DATA;\
157
h->data_received = 0;\
158
} \
159
} while (0)
160
161
#define handle_abort(h) \
162
do {\
163
h->shift_reg = fast_abort[h->ffbit_shift - 1];\
164
h->hdlc_bits1 = h->ffbit_shift - 2;\
165
if (h->hdlc_bits1 < 0)\
166
h->hdlc_bits1 = 0;\
167
h->data_bits = h->ffbit_shift - 1;\
168
h->state = HDLC_GET_DATA;\
169
h->data_received = 0;\
170
} while (0)
171
172
*count = slen;
173
174
while (slen > 0) {
175
if (hdlc->bit_shift == 0) {
176
/* the code is for bitreverse streams */
177
if (hdlc->do_bitreverse == 0)
178
hdlc->cbin = bitrev8(*src++);
179
else
180
hdlc->cbin = *src++;
181
slen--;
182
hdlc->bit_shift = 8;
183
if (hdlc->do_adapt56)
184
hdlc->bit_shift--;
185
}
186
187
switch (hdlc->state) {
188
case STOPPED:
189
return 0;
190
case HDLC_FAST_IDLE:
191
if (hdlc->cbin == 0xff) {
192
hdlc->bit_shift = 0;
193
break;
194
}
195
hdlc->state = HDLC_GET_FLAG_B0;
196
hdlc->hdlc_bits1 = 0;
197
hdlc->bit_shift = 8;
198
break;
199
case HDLC_GET_FLAG_B0:
200
if (!(hdlc->cbin & 0x80)) {
201
hdlc->state = HDLC_GETFLAG_B1A6;
202
hdlc->hdlc_bits1 = 0;
203
} else {
204
if ((!hdlc->do_adapt56) &&
205
(++hdlc->hdlc_bits1 >= 8) &&
206
(hdlc->bit_shift == 1))
207
hdlc->state = HDLC_FAST_IDLE;
208
}
209
hdlc->cbin <<= 1;
210
hdlc->bit_shift--;
211
break;
212
case HDLC_GETFLAG_B1A6:
213
if (hdlc->cbin & 0x80) {
214
hdlc->hdlc_bits1++;
215
if (hdlc->hdlc_bits1 == 6)
216
hdlc->state = HDLC_GETFLAG_B7;
217
} else
218
hdlc->hdlc_bits1 = 0;
219
hdlc->cbin <<= 1;
220
hdlc->bit_shift--;
221
break;
222
case HDLC_GETFLAG_B7:
223
if (hdlc->cbin & 0x80) {
224
hdlc->state = HDLC_GET_FLAG_B0;
225
} else {
226
hdlc->state = HDLC_GET_DATA;
227
hdlc->crc = 0xffff;
228
hdlc->shift_reg = 0;
229
hdlc->hdlc_bits1 = 0;
230
hdlc->data_bits = 0;
231
hdlc->data_received = 0;
232
}
233
hdlc->cbin <<= 1;
234
hdlc->bit_shift--;
235
break;
236
case HDLC_GET_DATA:
237
if (hdlc->cbin & 0x80) {
238
hdlc->hdlc_bits1++;
239
switch (hdlc->hdlc_bits1) {
240
case 6:
241
break;
242
case 7:
243
if (hdlc->data_received)
244
/* bad frame */
245
status = -HDLC_FRAMING_ERROR;
246
if (!hdlc->do_adapt56) {
247
if (hdlc->cbin == fast_abort
248
[hdlc->bit_shift + 1]) {
249
hdlc->state =
250
HDLC_FAST_IDLE;
251
hdlc->bit_shift = 1;
252
break;
253
}
254
} else
255
hdlc->state = HDLC_GET_FLAG_B0;
256
break;
257
default:
258
hdlc->shift_reg >>= 1;
259
hdlc->shift_reg |= 0x80;
260
hdlc->data_bits++;
261
break;
262
}
263
} else {
264
switch (hdlc->hdlc_bits1) {
265
case 5:
266
break;
267
case 6:
268
if (hdlc->data_received)
269
status = check_frame(hdlc);
270
hdlc->crc = 0xffff;
271
hdlc->shift_reg = 0;
272
hdlc->data_bits = 0;
273
if (!hdlc->do_adapt56)
274
handle_fast_flag(hdlc);
275
else {
276
hdlc->state = HDLC_GET_DATA;
277
hdlc->data_received = 0;
278
}
279
break;
280
default:
281
hdlc->shift_reg >>= 1;
282
hdlc->data_bits++;
283
break;
284
}
285
hdlc->hdlc_bits1 = 0;
286
}
287
if (status) {
288
hdlc->dstpos = 0;
289
*count -= slen;
290
hdlc->cbin <<= 1;
291
hdlc->bit_shift--;
292
return status;
293
}
294
if (hdlc->data_bits == 8) {
295
hdlc->data_bits = 0;
296
hdlc->data_received = 1;
297
hdlc->crc = crc_ccitt_byte(hdlc->crc,
298
hdlc->shift_reg);
299
300
/* good byte received */
301
if (hdlc->dstpos < dsize)
302
dst[hdlc->dstpos++] = hdlc->shift_reg;
303
else {
304
/* frame too long */
305
status = -HDLC_LENGTH_ERROR;
306
hdlc->dstpos = 0;
307
}
308
}
309
hdlc->cbin <<= 1;
310
hdlc->bit_shift--;
311
break;
312
case HDLC_FAST_FLAG:
313
if (hdlc->cbin == hdlc->ffvalue) {
314
hdlc->bit_shift = 0;
315
break;
316
} else {
317
if (hdlc->cbin == 0xff) {
318
hdlc->state = HDLC_FAST_IDLE;
319
hdlc->bit_shift = 0;
320
} else if (hdlc->ffbit_shift == 8) {
321
hdlc->state = HDLC_GETFLAG_B7;
322
break;
323
} else
324
handle_abort(hdlc);
325
}
326
break;
327
default:
328
break;
329
}
330
}
331
*count -= slen;
332
return 0;
333
}
334
EXPORT_SYMBOL(isdnhdlc_decode);
335
/*
336
isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
337
338
The bit stream starts with a beginning flag (01111110). After
339
that each byte is added to the bit stream with bit stuffing added
340
(0 after 5 1's).
341
When the last byte has been removed from the source buffer, the
342
CRC (2 bytes is added) and the frame terminates with the ending flag.
343
For the dchannel, the idle character (all 1's) is also added at the end.
344
If this function is called with empty source buffer (slen=0), flags or
345
idle character will be generated.
346
347
src - source buffer
348
slen - source buffer length
349
count - number of bytes removed (encoded) from source buffer
350
dst _ destination buffer
351
dsize - destination buffer size
352
returns - number of encoded bytes in the destination buffer
353
*/
354
int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
355
int *count, u8 *dst, int dsize)
356
{
357
static const unsigned char xfast_flag_value[] = {
358
0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
359
};
360
361
int len = 0;
362
363
*count = slen;
364
365
/* special handling for one byte frames */
366
if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
367
hdlc->state = HDLC_SENDFLAG_ONE;
368
while (dsize > 0) {
369
if (hdlc->bit_shift == 0) {
370
if (slen && !hdlc->do_closing) {
371
hdlc->shift_reg = *src++;
372
slen--;
373
if (slen == 0)
374
/* closing sequence, CRC + flag(s) */
375
hdlc->do_closing = 1;
376
hdlc->bit_shift = 8;
377
} else {
378
if (hdlc->state == HDLC_SEND_DATA) {
379
if (hdlc->data_received) {
380
hdlc->state = HDLC_SEND_CRC1;
381
hdlc->crc ^= 0xffff;
382
hdlc->bit_shift = 8;
383
hdlc->shift_reg =
384
hdlc->crc & 0xff;
385
} else if (!hdlc->do_adapt56)
386
hdlc->state =
387
HDLC_SEND_FAST_FLAG;
388
else
389
hdlc->state =
390
HDLC_SENDFLAG_B0;
391
}
392
393
}
394
}
395
396
switch (hdlc->state) {
397
case STOPPED:
398
while (dsize--)
399
*dst++ = 0xff;
400
return dsize;
401
case HDLC_SEND_FAST_FLAG:
402
hdlc->do_closing = 0;
403
if (slen == 0) {
404
/* the code is for bitreverse streams */
405
if (hdlc->do_bitreverse == 0)
406
*dst++ = bitrev8(hdlc->ffvalue);
407
else
408
*dst++ = hdlc->ffvalue;
409
len++;
410
dsize--;
411
break;
412
}
413
/* fall through */
414
case HDLC_SENDFLAG_ONE:
415
if (hdlc->bit_shift == 8) {
416
hdlc->cbin = hdlc->ffvalue >>
417
(8 - hdlc->data_bits);
418
hdlc->state = HDLC_SEND_DATA;
419
hdlc->crc = 0xffff;
420
hdlc->hdlc_bits1 = 0;
421
hdlc->data_received = 1;
422
}
423
break;
424
case HDLC_SENDFLAG_B0:
425
hdlc->do_closing = 0;
426
hdlc->cbin <<= 1;
427
hdlc->data_bits++;
428
hdlc->hdlc_bits1 = 0;
429
hdlc->state = HDLC_SENDFLAG_B1A6;
430
break;
431
case HDLC_SENDFLAG_B1A6:
432
hdlc->cbin <<= 1;
433
hdlc->data_bits++;
434
hdlc->cbin++;
435
if (++hdlc->hdlc_bits1 == 6)
436
hdlc->state = HDLC_SENDFLAG_B7;
437
break;
438
case HDLC_SENDFLAG_B7:
439
hdlc->cbin <<= 1;
440
hdlc->data_bits++;
441
if (slen == 0) {
442
hdlc->state = HDLC_SENDFLAG_B0;
443
break;
444
}
445
if (hdlc->bit_shift == 8) {
446
hdlc->state = HDLC_SEND_DATA;
447
hdlc->crc = 0xffff;
448
hdlc->hdlc_bits1 = 0;
449
hdlc->data_received = 1;
450
}
451
break;
452
case HDLC_SEND_FIRST_FLAG:
453
hdlc->data_received = 1;
454
if (hdlc->data_bits == 8) {
455
hdlc->state = HDLC_SEND_DATA;
456
hdlc->crc = 0xffff;
457
hdlc->hdlc_bits1 = 0;
458
break;
459
}
460
hdlc->cbin <<= 1;
461
hdlc->data_bits++;
462
if (hdlc->shift_reg & 0x01)
463
hdlc->cbin++;
464
hdlc->shift_reg >>= 1;
465
hdlc->bit_shift--;
466
if (hdlc->bit_shift == 0) {
467
hdlc->state = HDLC_SEND_DATA;
468
hdlc->crc = 0xffff;
469
hdlc->hdlc_bits1 = 0;
470
}
471
break;
472
case HDLC_SEND_DATA:
473
hdlc->cbin <<= 1;
474
hdlc->data_bits++;
475
if (hdlc->hdlc_bits1 == 5) {
476
hdlc->hdlc_bits1 = 0;
477
break;
478
}
479
if (hdlc->bit_shift == 8)
480
hdlc->crc = crc_ccitt_byte(hdlc->crc,
481
hdlc->shift_reg);
482
if (hdlc->shift_reg & 0x01) {
483
hdlc->hdlc_bits1++;
484
hdlc->cbin++;
485
hdlc->shift_reg >>= 1;
486
hdlc->bit_shift--;
487
} else {
488
hdlc->hdlc_bits1 = 0;
489
hdlc->shift_reg >>= 1;
490
hdlc->bit_shift--;
491
}
492
break;
493
case HDLC_SEND_CRC1:
494
hdlc->cbin <<= 1;
495
hdlc->data_bits++;
496
if (hdlc->hdlc_bits1 == 5) {
497
hdlc->hdlc_bits1 = 0;
498
break;
499
}
500
if (hdlc->shift_reg & 0x01) {
501
hdlc->hdlc_bits1++;
502
hdlc->cbin++;
503
hdlc->shift_reg >>= 1;
504
hdlc->bit_shift--;
505
} else {
506
hdlc->hdlc_bits1 = 0;
507
hdlc->shift_reg >>= 1;
508
hdlc->bit_shift--;
509
}
510
if (hdlc->bit_shift == 0) {
511
hdlc->shift_reg = (hdlc->crc >> 8);
512
hdlc->state = HDLC_SEND_CRC2;
513
hdlc->bit_shift = 8;
514
}
515
break;
516
case HDLC_SEND_CRC2:
517
hdlc->cbin <<= 1;
518
hdlc->data_bits++;
519
if (hdlc->hdlc_bits1 == 5) {
520
hdlc->hdlc_bits1 = 0;
521
break;
522
}
523
if (hdlc->shift_reg & 0x01) {
524
hdlc->hdlc_bits1++;
525
hdlc->cbin++;
526
hdlc->shift_reg >>= 1;
527
hdlc->bit_shift--;
528
} else {
529
hdlc->hdlc_bits1 = 0;
530
hdlc->shift_reg >>= 1;
531
hdlc->bit_shift--;
532
}
533
if (hdlc->bit_shift == 0) {
534
hdlc->shift_reg = 0x7e;
535
hdlc->state = HDLC_SEND_CLOSING_FLAG;
536
hdlc->bit_shift = 8;
537
}
538
break;
539
case HDLC_SEND_CLOSING_FLAG:
540
hdlc->cbin <<= 1;
541
hdlc->data_bits++;
542
if (hdlc->hdlc_bits1 == 5) {
543
hdlc->hdlc_bits1 = 0;
544
break;
545
}
546
if (hdlc->shift_reg & 0x01)
547
hdlc->cbin++;
548
hdlc->shift_reg >>= 1;
549
hdlc->bit_shift--;
550
if (hdlc->bit_shift == 0) {
551
hdlc->ffvalue =
552
xfast_flag_value[hdlc->data_bits];
553
if (hdlc->dchannel) {
554
hdlc->ffvalue = 0x7e;
555
hdlc->state = HDLC_SEND_IDLE1;
556
hdlc->bit_shift = 8-hdlc->data_bits;
557
if (hdlc->bit_shift == 0)
558
hdlc->state =
559
HDLC_SEND_FAST_IDLE;
560
} else {
561
if (!hdlc->do_adapt56) {
562
hdlc->state =
563
HDLC_SEND_FAST_FLAG;
564
hdlc->data_received = 0;
565
} else {
566
hdlc->state = HDLC_SENDFLAG_B0;
567
hdlc->data_received = 0;
568
}
569
/* Finished this frame, send flags */
570
if (dsize > 1)
571
dsize = 1;
572
}
573
}
574
break;
575
case HDLC_SEND_IDLE1:
576
hdlc->do_closing = 0;
577
hdlc->cbin <<= 1;
578
hdlc->cbin++;
579
hdlc->data_bits++;
580
hdlc->bit_shift--;
581
if (hdlc->bit_shift == 0) {
582
hdlc->state = HDLC_SEND_FAST_IDLE;
583
hdlc->bit_shift = 0;
584
}
585
break;
586
case HDLC_SEND_FAST_IDLE:
587
hdlc->do_closing = 0;
588
hdlc->cbin = 0xff;
589
hdlc->data_bits = 8;
590
if (hdlc->bit_shift == 8) {
591
hdlc->cbin = 0x7e;
592
hdlc->state = HDLC_SEND_FIRST_FLAG;
593
} else {
594
/* the code is for bitreverse streams */
595
if (hdlc->do_bitreverse == 0)
596
*dst++ = bitrev8(hdlc->cbin);
597
else
598
*dst++ = hdlc->cbin;
599
hdlc->bit_shift = 0;
600
hdlc->data_bits = 0;
601
len++;
602
dsize = 0;
603
}
604
break;
605
default:
606
break;
607
}
608
if (hdlc->do_adapt56) {
609
if (hdlc->data_bits == 7) {
610
hdlc->cbin <<= 1;
611
hdlc->cbin++;
612
hdlc->data_bits++;
613
}
614
}
615
if (hdlc->data_bits == 8) {
616
/* the code is for bitreverse streams */
617
if (hdlc->do_bitreverse == 0)
618
*dst++ = bitrev8(hdlc->cbin);
619
else
620
*dst++ = hdlc->cbin;
621
hdlc->data_bits = 0;
622
len++;
623
dsize--;
624
}
625
}
626
*count -= slen;
627
628
return len;
629
}
630
EXPORT_SYMBOL(isdnhdlc_encode);
631
632