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