]> git.ozlabs.org Git - ppp.git/blob - modules/ppp_ahdlc.c
Re-wrote async HDLC encoding/decoding algorithms, mostly due to some
[ppp.git] / modules / ppp_ahdlc.c
1 /*
2  * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
3  *
4  * Re-written by Adi Masputra <adi.masputra@sun.com>, based on 
5  * the original ppp_ahdlc.c
6  *
7  * Copyright (c) 2000 by Sun Microsystems, Inc.
8  * All rights reserved.
9  *
10  * Permission to use, copy, modify, and distribute this software and its
11  * documentation is hereby granted, provided that the above copyright
12  * notice appears in all copies.  
13  *
14  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
15  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
16  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
18  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
19  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
20  *
21  * Copyright (c) 1994 The Australian National University.
22  * All rights reserved.
23  *
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, provided that the above copyright
26  * notice appears in all copies.  This software is provided without any
27  * warranty, express or implied. The Australian National University
28  * makes no representations about the suitability of this software for
29  * any purpose.
30  *
31  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
32  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
33  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
34  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
38  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
40  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
41  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
42  * OR MODIFICATIONS.
43  *
44  * $Id: ppp_ahdlc.c,v 1.12 2000/01/21 01:04:56 masputra Exp $
45  */
46
47 /*
48  * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
49  */
50 #include <sys/types.h>
51 #include <sys/param.h>
52 #include <sys/stream.h>
53 #include <sys/errno.h>
54
55 #ifdef SVR4
56 #include <sys/conf.h>
57 #include <sys/kmem.h>
58 #include <sys/cmn_err.h>
59 #include <sys/ddi.h>
60 #else
61 #include <sys/user.h>
62 #ifdef __osf__
63 #include <sys/cmn_err.h>
64 #endif
65 #endif /* SVR4 */
66
67 #include <net/ppp_defs.h>
68 #include <net/pppio.h>
69 #include "ppp_mod.h"
70
71 /*
72  * Right now, mutex is only enabled for Solaris 2.x
73  */
74 #if defined(SOL2)
75 #define USE_MUTEX
76 #endif /* SOL2 */
77
78 MOD_OPEN_DECL(ahdlc_open);
79 MOD_CLOSE_DECL(ahdlc_close);
80 static int ahdlc_wput __P((queue_t *, mblk_t *));
81 static int ahdlc_rput __P((queue_t *, mblk_t *));
82 static void ahdlc_encode __P((queue_t *, mblk_t *));
83 static void ahdlc_decode __P((queue_t *, mblk_t *));
84 static int msg_byte __P((mblk_t *, unsigned int));
85
86 #if defined(SOL2)
87 /*
88  * Don't send HDLC start flag is last transmit is within 1.5 seconds -
89  * FLAG_TIME is defined is microseconds
90  */
91 #define FLAG_TIME   1500
92 #define ABS(x)      (x >= 0 ? x : (-x))
93 #endif /* SOL2 */
94
95 /*
96  * Extract byte i of message mp 
97  */
98 #define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
99                          msg_byte((mp), (i)))
100
101 /* 
102  * Is this LCP packet one we have to transmit using LCP defaults? 
103  */
104 #define LCP_USE_DFLT(mp)        (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
105
106 /*
107  * Standard STREAMS declarations
108  */
109 static struct module_info minfo = {
110     0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
111 };
112
113 static struct qinit rinit = {
114     ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
115 };
116
117 static struct qinit winit = {
118     ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
119 };
120
121 #if defined(SVR4) && !defined(SOL2)
122 int phdldevflag = 0;
123 #define ppp_ahdlcinfo phdlinfo
124 #endif /* defined(SVR4) && !defined(SOL2) */
125
126 struct streamtab ppp_ahdlcinfo = {
127     &rinit,                         /* ptr to st_rdinit */
128     &winit,                         /* ptr to st_wrinit */
129     NULL,                           /* ptr to st_muxrinit */
130     NULL,                           /* ptr to st_muxwinit */
131 #ifdef _SunOS4
132     NULL                            /* ptr to ptr to st_modlist */
133 #endif /* _SunOS4 */
134 };
135
136 /*
137  * Per-stream state structure
138  */
139 typedef struct ahdlc_state {
140 #if defined(USE_MUTEX)
141     kmutex_t        lock;                   /* lock for this structure */
142 #endif /* USE_MUTEX */
143     int             flags;                  /* link flags */
144     mblk_t          *rx_buf;                /* ptr to receive buffer */
145     int             rx_buf_size;            /* receive buffer size */
146     ushort_t        infcs;                  /* calculated rx HDLC FCS */
147     u_int32_t       xaccm[8];               /* 256-bit xmit ACCM */
148     u_int32_t       raccm;                  /* 32-bit rcv ACCM */
149     int             mtu;                    /* interface MTU */
150     int             mru;                    /* link MRU */
151     int             unit;                   /* current PPP unit number */
152     struct pppstat  stats;                  /* statistic structure */
153 #if defined(SOL2)
154     clock_t         flag_time;              /* time in usec between flags */
155     clock_t         lbolt;                  /* last updated lbolt */
156 #endif /* SOL2 */
157 } ahdlc_state_t;
158
159 /*
160  * Values for flags 
161  */
162 #define ESCAPED         0x100   /* last saw escape char on input */
163 #define IFLUSH          0x200   /* flushing input due to error */
164
165 /* 
166  * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. 
167  */
168 #define RCV_FLAGS       (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
169
170 /*
171  * FCS lookup table as calculated by genfcstab.
172  */
173 static u_short fcstab[256] = {
174         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
175         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
176         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
177         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
178         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
179         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
180         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
181         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
182         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
183         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
184         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
185         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
186         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
187         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
188         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
189         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
190         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
191         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
192         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
193         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
194         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
195         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
196         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
197         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
198         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
199         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
200         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
201         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
202         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
203         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
204         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
205         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
206 };
207
208 static u_int32_t paritytab[8] =
209 {
210         0x96696996, 0x69969669, 0x69969669, 0x96696996,
211         0x69969669, 0x96696996, 0x96696996, 0x69969669
212 };
213
214 /*
215  * STREAMS module open (entry) point
216  */
217 MOD_OPEN(ahdlc_open)
218 {
219     ahdlc_state_t   *state;
220
221     /*
222      * Return if it's already opened
223      */
224     if (q->q_ptr) {
225         return 0;
226     }
227
228     /*
229      * This can only be opened as a module
230      */
231     if (sflag != MODOPEN) {
232         return 0;
233     }
234
235     state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
236     if (state == 0)
237         OPEN_ERROR(ENOSR);
238     bzero((caddr_t) state, sizeof(ahdlc_state_t));
239
240     q->q_ptr     = (caddr_t) state;
241     WR(q)->q_ptr = (caddr_t) state;
242
243 #if defined(USE_MUTEX)
244     mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
245     mutex_enter(&state->lock);
246 #endif /* USE_MUTEX */
247
248     state->xaccm[0] = ~0;           /* escape 0x00 through 0x1f */
249     state->xaccm[3] = 0x60000000;   /* escape 0x7d and 0x7e */
250     state->mru      = PPP_MRU;      /* default of 1500 bytes */
251 #if defined(SOL2)
252     state->flag_time = drv_usectohz(FLAG_TIME);
253 #endif /* SOL2 */
254
255 #if defined(USE_MUTEX)
256     mutex_exit(&state->lock);
257 #endif /* USE_MUTEX */  
258
259     qprocson(q);
260     
261     return 0;
262 }
263
264 /*
265  * STREAMS module close (exit) point
266  */
267 MOD_CLOSE(ahdlc_close)
268 {
269     ahdlc_state_t   *state;
270
271     qprocsoff(q);
272
273     state = (ahdlc_state_t *) q->q_ptr;
274
275     if (state == 0) {
276         DPRINT("state == 0 in ahdlc_close\n");
277         return 0;
278     }
279
280 #if defined(USE_MUTEX)
281     mutex_enter(&state->lock);
282 #endif /* USE_MUTEX */
283
284     if (state->rx_buf != 0) {
285         freemsg(state->rx_buf);
286         state->rx_buf = 0;
287     }
288
289 #if defined(USE_MUTEX)
290     mutex_exit(&state->lock);
291     mutex_destroy(&state->lock);
292 #endif /* USE_MUTEX */
293
294     FREE(q->q_ptr, sizeof(ahdlc_state_t));
295     q->q_ptr         = NULL;
296     OTHERQ(q)->q_ptr = NULL;
297     
298     return 0;
299 }
300
301 /*
302  * Write side put routine
303  */
304 static int
305 ahdlc_wput(q, mp)
306     queue_t     *q;
307     mblk_t      *mp;
308 {
309     ahdlc_state_t       *state;
310     struct iocblk       *iop;
311     int                 error;
312     mblk_t              *np;
313     struct ppp_stats    *psp;
314
315     state = (ahdlc_state_t *) q->q_ptr;
316     if (state == 0) {
317         DPRINT("state == 0 in ahdlc_wput\n");
318         freemsg(mp);
319         return 0;
320     }
321
322     switch (mp->b_datap->db_type) {
323     case M_DATA:
324         /*
325          * A data packet - do character-stuffing and FCS, and
326          * send it onwards.
327          */
328         ahdlc_encode(q, mp);
329         freemsg(mp);
330         break;
331
332     case M_IOCTL:
333         iop = (struct iocblk *) mp->b_rptr;
334         error = EINVAL;
335         switch (iop->ioc_cmd) {
336         case PPPIO_XACCM:
337             if ((iop->ioc_count < sizeof(u_int32_t)) || 
338                 (iop->ioc_count > sizeof(ext_accm))) {
339                 break;
340             }
341             if (mp->b_cont == 0) {
342                 DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
343                 break;
344             }
345 #if defined(USE_MUTEX)
346             mutex_enter(&state->lock);
347 #endif /* USE_MUTEX */
348             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
349                   iop->ioc_count);
350             state->xaccm[2] &= ~0x40000000;     /* don't escape 0x5e */
351             state->xaccm[3] |= 0x60000000;      /* do escape 0x7d, 0x7e */
352 #if defined(USE_MUTEX)
353             mutex_exit(&state->lock);
354 #endif /* USE_MUTEX */
355             iop->ioc_count = 0;
356             error = 0;
357             break;
358
359         case PPPIO_RACCM:
360             if (iop->ioc_count != sizeof(u_int32_t))
361                 break;
362             if (mp->b_cont == 0) {
363                 DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
364                 break;
365             }
366 #if defined(USE_MUTEX)
367             mutex_enter(&state->lock);
368 #endif /* USE_MUTEX */
369             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
370                   sizeof(u_int32_t));
371 #if defined(USE_MUTEX)
372             mutex_exit(&state->lock);
373 #endif /* USE_MUTEX */
374             iop->ioc_count = 0;
375             error = 0;
376             break;
377
378         case PPPIO_GCLEAN:
379             np = allocb(sizeof(int), BPRI_HI);
380             if (np == 0) {
381                 error = ENOSR;
382                 break;
383             }
384             if (mp->b_cont != 0)
385                 freemsg(mp->b_cont);
386             mp->b_cont = np;
387 #if defined(USE_MUTEX)
388             mutex_enter(&state->lock);
389 #endif /* USE_MUTEX */
390             *(int *)np->b_wptr = state->flags & RCV_FLAGS;
391 #if defined(USE_MUTEX)
392             mutex_exit(&state->lock);
393 #endif /* USE_MUTEX */
394             np->b_wptr += sizeof(int);
395             iop->ioc_count = sizeof(int);
396             error = 0;
397             break;
398
399         case PPPIO_GETSTAT:
400             np = allocb(sizeof(struct ppp_stats), BPRI_HI);
401             if (np == 0) {
402                 error = ENOSR;
403                 break;
404             }
405             if (mp->b_cont != 0)
406                 freemsg(mp->b_cont);
407             mp->b_cont = np;
408             psp = (struct ppp_stats *) np->b_wptr;
409             np->b_wptr += sizeof(struct ppp_stats);
410             bzero((caddr_t)psp, sizeof(struct ppp_stats));
411             psp->p = state->stats;
412             iop->ioc_count = sizeof(struct ppp_stats);
413             error = 0;
414             break;
415
416         case PPPIO_LASTMOD:
417             /* we knew this anyway */
418             error = 0;
419             break;
420
421         default:
422             error = -1;
423             break;
424         }
425
426         if (error < 0)
427             putnext(q, mp);
428         else if (error == 0) {
429             mp->b_datap->db_type = M_IOCACK;
430             qreply(q, mp);
431         } else {
432             mp->b_datap->db_type = M_IOCNAK;
433             iop->ioc_count = 0;
434             iop->ioc_error = error;
435             qreply(q, mp);
436         }
437         break;
438
439     case M_CTL:
440         switch (*mp->b_rptr) {
441         case PPPCTL_MTU:
442 #if defined(USE_MUTEX)
443             mutex_enter(&state->lock);
444 #endif /* USE_MUTEX */
445             state->mtu = ((unsigned short *)mp->b_rptr)[1];
446 #if defined(USE_MUTEX)
447             mutex_exit(&state->lock);
448 #endif /* USE_MUTEX */
449             freemsg(mp);
450             break;
451         case PPPCTL_MRU:
452 #if defined(USE_MUTEX)
453             mutex_enter(&state->lock);
454 #endif /* USE_MUTEX */
455             state->mru = ((unsigned short *)mp->b_rptr)[1];
456 #if defined(USE_MUTEX)
457             mutex_exit(&state->lock);
458 #endif /* USE_MUTEX */
459             freemsg(mp);
460             break;
461         case PPPCTL_UNIT:
462 #if defined(USE_MUTEX)
463             mutex_enter(&state->lock);
464 #endif /* USE_MUTEX */
465             state->unit = mp->b_rptr[1];
466 #if defined(USE_MUTEX)
467             mutex_exit(&state->lock);
468 #endif /* USE_MUTEX */
469             break;
470         default:
471             putnext(q, mp);
472         }
473         break;
474
475     default:
476         putnext(q, mp);
477     }
478
479     return 0;
480 }
481
482 /*
483  * Read side put routine
484  */
485 static int
486 ahdlc_rput(q, mp)
487     queue_t *q;
488     mblk_t  *mp;
489 {
490     ahdlc_state_t *state;
491
492     state = (ahdlc_state_t *) q->q_ptr;
493     if (state == 0) {
494         DPRINT("state == 0 in ahdlc_rput\n");
495         freemsg(mp);
496         return 0;
497     }
498
499     switch (mp->b_datap->db_type) {
500     case M_DATA:
501         ahdlc_decode(q, mp);
502         freemsg(mp);
503         break;
504
505     case M_HANGUP:
506 #if defined(USE_MUTEX)
507         mutex_enter(&state->lock);
508 #endif /* USE_MUTEX */
509         if (state->rx_buf != 0) {
510             /* XXX would like to send this up for debugging */
511             freemsg(state->rx_buf);
512             state->rx_buf = 0;
513         }
514         state->flags = IFLUSH;
515 #if defined(USE_MUTEX)
516         mutex_exit(&state->lock);
517 #endif /* USE_MUTEX */
518         putnext(q, mp);
519         break;
520
521     default:
522         putnext(q, mp);
523     }
524     return 0;
525 }
526
527 /*
528  * Extract bit c from map m, to determine if c needs to be escaped
529  */
530 #define IN_TX_MAP(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
531
532 static void
533 ahdlc_encode(q, mp)
534     queue_t     *q;
535     mblk_t      *mp;
536 {
537     ahdlc_state_t       *state;
538     u_int32_t           *xaccm, loc_xaccm[8];
539     ushort_t            fcs;
540     size_t              outmp_len;
541     mblk_t              *outmp, *tmp;
542     uchar_t             *dp, fcs_val;
543     int                 is_lcp, code;
544 #if defined(SOL2)
545     clock_t             lbolt;
546 #endif /* SOL2 */
547
548     if (msgdsize(mp) < 4) {
549         return;
550     }
551
552     state = (ahdlc_state_t *)q->q_ptr;
553 #if defined(USE_MUTEX)
554     mutex_enter(&state->lock);
555 #endif /* USE_MUTEX */
556
557     /*
558      * Allocate an output buffer large enough to handle a case where all
559      * characters need to be escaped
560      */
561     outmp_len = (msgdsize(mp)    << 1) +                /* input block x 2 */
562                 (sizeof(fcs)     << 2) +                /* HDLC FCS x 4 */
563                 (sizeof(uchar_t) << 1);                 /* HDLC flags x 2 */
564
565     outmp = allocb(outmp_len, BPRI_MED);
566     if (outmp == NULL) {
567         state->stats.ppp_oerrors++;
568 #if defined(USE_MUTEX)
569         mutex_exit(&state->lock);
570 #endif /* USE_MUTEX */
571         putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
572         return;
573     }
574
575 #if defined(SOL2)
576     /*
577      * Check if our last transmit happenned within flag_time, using
578      * the system's LBOLT value in clock ticks
579      */
580     if (drv_getparm(LBOLT, &lbolt) != -1) {
581         if (ABS((clock32_t)lbolt - state->lbolt) > state->flag_time) {
582             *outmp->b_wptr++ = PPP_FLAG;
583         } 
584         state->lbolt = lbolt;
585     } else {
586         *outmp->b_wptr++ = PPP_FLAG;
587     }
588 #else
589     /*
590      * If the driver below still has a message to process, skip the
591      * HDLC flag, otherwise, put one in the beginning
592      */
593     if (qsize(q->q_next) == 0) {
594         *outmp->b_wptr++ = PPP_FLAG;
595     }
596 #endif
597
598     /*
599      * All control characters must be escaped for LCP packets with code
600      * values between 1 (Conf-Req) and 7 (Code-Rej).
601      */
602     is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) && 
603               (MSG_BYTE(mp, 1) == PPP_UI) && 
604               (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
605               (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
606               LCP_USE_DFLT(mp));
607
608     xaccm = state->xaccm;
609     if (is_lcp) {
610         bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
611         loc_xaccm[0] = ~0;      /* force escape on 0x00 through 0x1f */
612         xaccm = loc_xaccm;
613     }
614
615     fcs = PPP_INITFCS;          /* Initial FCS is 0xffff */
616
617     /*
618      * Process this block and the rest (if any) attached to the this one
619      */
620     for (tmp = mp; tmp; tmp = tmp->b_cont) {
621         if (tmp->b_datap->db_type == M_DATA) {
622             for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
623                 fcs = PPP_FCS(fcs, *dp);
624                 if (IN_TX_MAP(*dp, xaccm)) {
625                     *outmp->b_wptr++ = PPP_ESCAPE;
626                     *outmp->b_wptr++ = *dp ^ PPP_TRANS;
627                 } else {
628                     *outmp->b_wptr++ = *dp;
629                 }
630             }
631         } else {
632             continue;   /* skip if db_type is something other than M_DATA */
633         }
634     }
635
636     /*
637      * Append the HDLC FCS, making sure that escaping is done on any
638      * necessary bytes
639      */
640     fcs_val = (fcs ^ 0xffff) & 0xff;
641     if (IN_TX_MAP(fcs_val, xaccm)) {
642         *outmp->b_wptr++ = PPP_ESCAPE;
643         *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
644     } else {
645         *outmp->b_wptr++ = fcs_val;
646     }
647
648     fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
649     if (IN_TX_MAP(fcs_val, xaccm)) {
650         *outmp->b_wptr++ = PPP_ESCAPE;
651         *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
652     } else {
653         *outmp->b_wptr++ = fcs_val;
654     }
655
656     /*
657      * And finally, append the HDLC flag, and send it away
658      */
659     *outmp->b_wptr++ = PPP_FLAG;
660
661     state->stats.ppp_obytes += msgdsize(outmp);
662     state->stats.ppp_opackets++;
663
664 #if defined(USE_MUTEX)
665     mutex_exit(&state->lock);
666 #endif /* USE_MUTEX */
667
668     putnext(q, outmp);
669     return;
670 }
671
672 /*
673  * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
674  */
675 #define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) < 0x20) && \
676                         (m) & (1 << (c)))
677
678 /*
679  * Process received characters.
680  */
681 static void
682 ahdlc_decode(q, mp)
683     queue_t *q;
684     mblk_t  *mp;
685 {
686     ahdlc_state_t   *state;
687     mblk_t          *om, *zmp;
688     uchar_t         *dp;
689     ushort_t        fcs;
690
691     /*
692      * In case the driver (or something below) doesn't send
693      * data upstream in one message block, concatenate everything
694      */
695     if (!((mp->b_wptr - mp->b_rptr == msgdsize(mp)) && 
696          ((intptr_t)mp->b_rptr % sizeof(intptr_t) == 0))) {
697
698         zmp = msgpullup(mp, -1);
699         freemsg(mp);
700         mp = zmp;
701         if (mp == 0)
702             return; 
703     }
704
705     state = (ahdlc_state_t *) q->q_ptr;
706
707 #if defined(USE_MUTEX)
708     mutex_enter(&state->lock);
709 #endif /* USE_MUTEX */
710
711     state->stats.ppp_ibytes += msgdsize(mp);
712
713     for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) {
714
715         /*
716          * This should detect the lack of 8-bit communication channel
717          * which is necessary for PPP to work. In addition, it also
718          * checks on the parity.
719          */
720         if (*dp & 0x80)
721             state->flags |= RCV_B7_1;
722         else
723             state->flags |= RCV_B7_0;
724
725         if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
726             state->flags |= RCV_ODDP;
727         else
728             state->flags |= RCV_EVNP;
729
730         /*
731          * So we have a HDLC flag ...
732          */
733         if (*dp == PPP_FLAG) {
734
735             /*
736              * If we think that it marks the beginning of the frame,
737              * then continue to process the next octects
738              */
739             if ((state->flags & IFLUSH) ||
740                 (state->rx_buf == 0) ||
741                 (msgdsize(state->rx_buf) == 0)) {
742
743                 state->flags &= ~IFLUSH;
744                 continue;
745             }
746
747             /*
748              * We get here because the above condition isn't true,
749              * in which case the HDLC flag was there to mark the end
750              * of the frame (or so we think)
751              */
752             om = state->rx_buf;
753
754             if (state->infcs == PPP_GOODFCS) {
755                 state->stats.ppp_ipackets++;
756                 adjmsg(om, -PPP_FCSLEN);
757                 putnext(q, om);
758             } else {
759                 DPRINT2("ppp%d: bad fcs (len=%d)\n",
760                     state->unit, msgdsize(state->rx_buf));
761                 freemsg(state->rx_buf);
762                 state->flags &= ~(IFLUSH | ESCAPED);
763                 state->stats.ppp_ierrors++;
764                 putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
765             }
766
767             state->rx_buf = 0;
768             continue;
769         }
770
771         if (state->flags & IFLUSH) {
772             continue;
773         }
774
775         /*
776          * Allocate a receive buffer, large enough to store a frame (after
777          * un-escaping) of at least 1500 octets. If MRU is negotiated to
778          * be more than the default, then allocate that much. In addition,
779          * we add an extra 32-bytes for a fudge factor
780          */ 
781         if (state->rx_buf == 0) {
782             state->rx_buf_size  = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
783             state->rx_buf_size += (sizeof(u_int32_t) << 3);
784             state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
785
786             /*
787              * If allocation fails, try again on the next frame
788              */
789             if (state->rx_buf == 0) {
790                 state->flags |= IFLUSH;
791                 continue;
792             }
793             state->flags &= ~(IFLUSH | ESCAPED);
794             state->infcs  = PPP_INITFCS;
795         }
796
797         if (*dp == PPP_ESCAPE) {
798             state->flags |= ESCAPED;
799             continue;
800         }
801
802         /*
803          * Make sure we un-escape the necessary characters, as well as the
804          * ones in our receive async control character map
805          */
806         if (state->flags & ESCAPED) {
807             *dp ^= PPP_TRANS;
808             state->flags &= ~ESCAPED;
809         } else if (IN_RX_MAP(*dp, state->raccm)) 
810             continue;
811
812         /*
813          * Unless the peer lied to us about the negotiated MRU, we should
814          * never get a frame which is too long. If it happens, toss it away
815          * and grab the next incoming one
816          */
817         if (msgdsize(state->rx_buf) < state->rx_buf_size) {
818             state->infcs = PPP_FCS(state->infcs, *dp);
819             *state->rx_buf->b_wptr++ = *dp;
820         } else {
821             DPRINT2("ppp%d: frame too long (%d)\n",
822                 state->unit, msgdsize(state->rx_buf));
823             freemsg(state->rx_buf);
824             state->rx_buf     = 0;
825             state->flags     |= IFLUSH;
826         }
827     }
828
829 #if defined(USE_MUTEX)
830     mutex_exit(&state->lock);
831 #endif /* USE_MUTEX */
832 }
833
834 static int
835 msg_byte(mp, i)
836     mblk_t *mp;
837     unsigned int i;
838 {
839     while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
840         mp = mp->b_cont;
841     if (mp == 0)
842         return -1;
843     return mp->b_rptr[i];
844 }