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