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