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