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