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