Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / layer1 / i4b_hdlc.h
1 /*
2  * Copyright (c) 2000 Hans Petter Selasky. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b_hdlc.h - software-HDLC header file
28  *      --------------------------------------
29  *
30  *      $Id: i4b_hdlc.h,v 1.5 2000/08/28 07:41:19 hm Exp $
31  *
32  * $FreeBSD: src/sys/i4b/layer1/i4b_hdlc.h,v 1.4.2.1 2001/08/10 14:08:36 obrien Exp $
33  *
34  *      last edit-date: [Wed Jul 19 09:41:13 2000]
35  *
36  *---------------------------------------------------------------------------*/
37
38 #ifndef _I4B_HDLC_H_
39 #define _I4B_HDLC_H_
40
41 /*---------------------------------------------------------------------------*
42  *      HDLC CRC table
43  *
44  * Usage:
45  *      crc = (HDLC_FCS_TAB[(u_char)(crc ^ byte of data)] ^ (u_char)(crc >> 8));
46  *
47  *      For more information see RFC 1662 (p. 10)
48  *---------------------------------------------------------------------------*/
49 const u_short HDLC_FCS_TAB[256] = { 0x0000, 
50         0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 
51         0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 
52         0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 
53         0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 
54         0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 
55         0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 
56         0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 
57         0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 
58         0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 
59         0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 
60         0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 
61         0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 
62         0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 
63         0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 
64         0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 
65         0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 
66         0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 
67         0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 
68         0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 
69         0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 
70         0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 
71         0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 
72         0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 
73         0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 
74         0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 
75         0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 
76         0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 
77         0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 
78         0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 
79         0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 
80         0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 
81         0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 
82 };
83
84 /*---------------------------------------------------------------------------*
85  *      HDLC bit table
86  *      ==============  
87  *
88  *      bits[0..3]:     A value which tells how many set bits there are at the
89  *                      beginning of the byte.
90  *
91  *      bits[4..7]:     Special bytes like 0x7e, 0x7d, 0xfd ... are flagged here
92  *                      NOTE: Special bytes also means 'abort' bytes (7 or more
93  *                            continuous set bits)
94  *
95  *      bits[8..11]:    A copy of bits[0..3] but only incremented by one.
96  *                      NOTE: 0x7e has value '8' instead of '0'. Internal reasons.
97  *
98  *      bits[12..15]:   A value which tells how many set bits there are at the
99  *                      end of the byte.
100  *                      NOTE: 0xff has both '8' incoming and '8' outgoing bits.
101  *
102  *---------------------------------------------------------------------------*/
103 const u_short HDLC_BIT_TAB[256] = { 0x0100, 
104         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
105         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, 
106         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
107         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0605, 0x0100, 
108         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
109         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, 
110         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
111         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0160, 0x0706, 0x0100, 
112         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
113         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, 
114         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
115         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0605, 0x0100, 
116         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
117         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, 
118         0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, 
119         0x0201, 0x0100, 0x0302, 0x01a0, 0x02a1, 0x0860, 0x0807, 0x1100, 
120         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, 
121         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1504, 0x1100, 
122         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, 
123         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1605, 0x1100, 
124         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, 
125         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1504, 0x1100, 
126         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, 
127         0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1160, 0x1706, 0x2100, 
128         0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2403, 0x2100, 
129         0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2504, 0x2100, 
130         0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2403, 0x2100, 
131         0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2605, 0x3100, 
132         0x3201, 0x3100, 0x3302, 0x3100, 0x3201, 0x3100, 0x3403, 0x3100, 
133         0x3201, 0x3100, 0x3302, 0x3100, 0x3201, 0x3100, 0x3504, 0x4100, 
134         0x4201, 0x4100, 0x4302, 0x4100, 0x4201, 0x4100, 0x4403, 0x5100, 
135         0x5201, 0x5100, 0x5302, 0x6180, 0x6281, 0x7150, 0x8908 
136 };
137
138 /*---------------------------------------------------------------------------*
139  *      HDLC_DECODE
140  *      ===========
141  *
142  *      u_char:  flag, blevel
143  *      u_short: crc, ib, tmp, tmp2, len
144  *
145  *      next: 'continue' or 'goto xxx'
146  *
147  *      cfr: complete frame
148  *      nfr: new frame
149  *           NOTE: must setup 'len' and 'dst', so that 'dst' may be written
150  *                 at most 'len' times.
151  *
152  *      rab: abort
153  *      rdd: read data (read byte is stored in 'tmp2')
154  *      rdo: overflow
155  *
156  *      d: dummy
157  *
158  *      NOTE: setting flag to '0' and len to '0' => recover from rdu
159  *      NOTE: bits[8 .. ] of tmp2 may be used to store custom data/flags
160  *      NOTE: these variables have to be 'suspended' / 'resumed' somehow:
161  *              flag, blevel, crc, ib, tmp, len
162  *      NOTE: zero is default value for all variables.
163  *      NOTE: each time 'dst' is written, 'len' is decreased by one.
164  *---------------------------------------------------------------------------*/
165
166 #define HDLC_DECODE(dst, len, tmp, tmp2, blevel, ib, crc, flag, rddcmd, nfrcmd, \
167                  cfrcmd, rabcmd, rdocmd, nextcmd, d)                            \
168                                                                                 \
169         rddcmd;                                                                 \
170                                                                                 \
171         ib  += HDLC_BIT_TAB[(u_char)tmp2];                                      \
172                                                                                 \
173         if ((u_char)ib >= 5)                                                    \
174         {                                                                       \
175                 if (ib & 0x20)          /* de-stuff (msb) */                    \
176                 {                                                               \
177                         if ((u_char)tmp2 == 0x7e) goto j0##d;                   \
178                         tmp2 += tmp2 & 0x7f;                                    \
179                         blevel--;                                               \
180                                                                                 \
181                         if ((ib += 0x100) & 0xc) tmp2 |= 1; /* */               \
182                 }                                                               \
183                                                                                 \
184                 ib &= ~0xe0;                                                    \
185                                                                                 \
186                 if ((u_char)ib == 6)    /* flag seq (lsb) */                    \
187                 {                                                               \
188                  j0##d: if (flag >= 2)                                          \
189                         {                                                       \
190                                 len += (4 - flag) & 3;  /* remove CRC bytes */  \
191                                 crc ^= 0xf0b8;                                  \
192                                 cfrcmd;                                         \
193                                 len = 0;                                        \
194                         }                                                       \
195                                                                                 \
196                         flag   = 1;                                             \
197                                                                                 \
198                         blevel = (ib >> 8) & 0xf;                               \
199                         tmp    = ((u_char)tmp2) >> blevel;                      \
200                         blevel = 8 - blevel;                                    \
201                                                                                 \
202                         ib >>= 12;                                              \
203                                                                                 \
204                         nextcmd;                                                \
205                 }                                                               \
206                 if ((u_char)ib >= 7)    /* abort (msb & lsb) */                 \
207                 {                                                               \
208                         if (flag >= 2)                                          \
209                         {                                                       \
210                                 rabcmd;                                         \
211                                 len = 0;                                        \
212                         }                                                       \
213                                                                                 \
214                         flag = 0;                                               \
215                                                                                 \
216                         ib >>= 12;                                              \
217                                                                                 \
218                         nextcmd;                                                \
219                 }                                                               \
220                 if ((u_char)ib == 5)    /* de-stuff (lsb) */                    \
221                 {                                                               \
222                         tmp2 = (tmp2 | (tmp2 + 1)) & ~0x1;                      \
223                         blevel--;                                               \
224                 }                                                               \
225                 if (blevel > 7)         /* EO - bits */                         \
226                 {                                                               \
227                         tmp |= (u_char)tmp2 >> (8 - (blevel &= 7));             \
228                                                                                 \
229                         ib >>= 12;                                              \
230                                                                                 \
231                         nextcmd;                                                \
232                 }                                                               \
233         }                                                                       \
234                                                                                 \
235         tmp |= (u_char)tmp2 << blevel;                                          \
236                                                                                 \
237         if (!len--)                                                             \
238         {                                                                       \
239                 len++;                                                          \
240                                                                                 \
241                 if (!flag++) { flag--; goto j5##d;} /* hunt mode */             \
242                                                                                 \
243                 switch (flag)                                                   \
244                 {   case 2:             /* new frame */                         \
245                         nfrcmd;                                                 \
246                         crc = -1;                                               \
247                         if (!len--) { len++; flag++; goto j4##d; }              \
248                         goto j3##d;                                             \
249                     case 3:             /* CRC (lsb's) */                       \
250                     case 4:             /* CRC (msb's) */                       \
251                         goto j4##d;                                             \
252                     case 5:             /* RDO */                               \
253                         rdocmd;                                                 \
254                         flag = 0;                                               \
255                         break;                                                  \
256                 }                                                               \
257         }                                                                       \
258         else                                                                    \
259         {                                                                       \
260          j3##d: dst = (u_char)tmp;                                              \
261          j4##d: crc = (HDLC_FCS_TAB[(u_char)(tmp ^ crc)] ^ (u_char)(crc >> 8)); \
262         }                                                                       \
263                                                                                 \
264  j5##d: ib >>= 12;                                                              \
265         tmp >>= 8;                                                              \
266
267 /*------ end of HDLC_DECODE -------------------------------------------------*/
268
269
270 /*---------------------------------------------------------------------------*
271  *      HDLC_ENCODE
272  *      ===========
273  *
274  *      u_char:  flag, src
275  *      u_short: tmp2, blevel, ib, crc, len
276  *      u_int:   tmp
277  *
278  *      gfr: This is the place where you free the last [mbuf] chain, and get
279  *           the next one. If a mbuf is available the code should setup 'len'
280  *           and 'src' so that 'src' may be read 'len' times. If no mbuf is
281  *           available leave 'len' and 'src' untouched.
282  *
283  *      wrd: write data (output = (u_char)tmp)
284  *
285  *      d: dummy
286  *
287  *      NOTE: setting flag to '-2' and len to '0' => abort bytes will be sent
288  *      NOTE: these variables have to be 'suspended' / 'resumed' somehow:
289  *              flag, blevel, crc, ib, tmp, len
290  *      NOTE: zero is default value for all variables.
291  *      NOTE: each time 'src' is read, 'len' is decreased by one.
292  *      NOTE: neither cmd's should exit through 'goto' or 'break' statements.
293  *---------------------------------------------------------------------------*/
294
295 #define HDLC_ENCODE(src, len, tmp, tmp2, blevel, ib, crc, flag, gfrcmd, wrdcmd, d) \
296                                                                                 \
297         if (blevel >= 0x800) { blevel -= 0x800; goto j4##d; }                   \
298                                                                                 \
299         if (!len--)                                                             \
300         {                                                                       \
301                 len++;                                                          \
302                                                                                 \
303                 switch(++flag)                                                  \
304                 { default:                      /* abort */                     \
305                         tmp  = blevel = 0;      /* zero is default */           \
306                         tmp2 = 0xff;                                            \
307                         goto j3##d;                                             \
308                   case 1:                       /* 1st time FS */               \
309                   case 2:                       /* 2nd time FS */               \
310                         tmp2 = 0x7e;                                            \
311                         goto j3##d;                                             \
312                   case 3:                                                       \
313                         gfrcmd;                 /* get new frame */             \
314                         if (!len--)                                             \
315                         {                                                       \
316                                 len++;                                          \
317                                 flag--;         /* don't proceed */             \
318                                 tmp2 = 0x7e;                                    \
319                                 goto j3##d;     /* final FS */                  \
320                         }                                                       \
321                         else                                                    \
322                         {                                                       \
323                                 crc = -1;                                       \
324                                 ib  = 0;                                        \
325                                 goto j1##d;     /* first byte */                \
326                         }                                                       \
327                   case 4:                                                       \
328                         crc ^= -1;                                              \
329                         tmp2 = (u_char)crc;                                     \
330                         goto j2##d;             /* CRC (lsb's) */               \
331                   case 5:                                                       \
332                         tmp2  = (u_char)(crc >> 8);                             \
333                         flag  = 1;                                              \
334                         goto j2##d;             /* CRC (msb's) */               \
335                 }                                                               \
336         }                                                                       \
337         else                                                                    \
338         { j1##d :                                                               \
339                 tmp2 = (u_char)src;                                             \
340                 crc =(HDLC_FCS_TAB[(u_char)(crc ^ tmp2)] ^ (u_char)(crc >> 8)); \
341           j2##d:                                                                \
342                                                                                 \
343                 ib >>= 12;                                                      \
344                 ib  += HDLC_BIT_TAB[(u_char)tmp2];                              \
345                                                                                 \
346                 if ((u_char)ib >= 5)    /* stuffing */                          \
347                 {                                                               \
348                         blevel &= ~0xff;                                        \
349                                                                                 \
350                         if (ib & 0xc0)          /* bit stuff (msb) */           \
351                         {                                                       \
352                                 tmp2 += tmp2 & (0xff * (ib & 0xc0));            \
353                                 ib %= 0x5000;                                   \
354                                 blevel++;                                       \
355                         }                                                       \
356                                                                                 \
357                         ib &= ~0xf0;                                            \
358                                                                                 \
359                         if ((u_char)ib >= 5)    /* bit stuff (lsb) */           \
360                         {                                                       \
361                                 tmp2 += tmp2 & ~0x1f >> ((ib - (ib >> 8) + 1)   \
362                                                                 & 7);           \
363                                 blevel++;                                       \
364                                                                                 \
365                                 if ((u_char)ib >= 10)   /* bit stuff (msb) */   \
366                                 {                                               \
367                                         tmp2 += tmp2 & ~0x7ff >> ((ib -         \
368                                                         (ib >> 8) + 1) & 7);    \
369                                         blevel++;                               \
370                                 }                                               \
371                                 if (ib & 0x8000)        /* bit walk */          \
372                                 {                                               \
373                                         ib = ((u_char)ib % 5) << 12;            \
374                                 }                                               \
375                         }                                                       \
376                                                                                 \
377                         tmp    |= tmp2 << (u_char)(blevel >> 8);                \
378                         blevel += (u_char)blevel << 8;                          \
379                 }                                                               \
380                 else            /* no stuffing */                               \
381                 {                                                               \
382                   j3##d:tmp    |= tmp2 << (u_char)(blevel >> 8);                \
383                 }                                                               \
384         }                                                                       \
385                                                                                 \
386  j4##d: wrdcmd;                                                                 \
387         tmp >>= 8;                                                              \
388
389 /*------ end of HDLC_ENCODE -------------------------------------------------*/
390
391
392 #endif /* _I4B_HDLC_H_ */
393