]> git.ozlabs.org Git - ppp.git/blob - solaris/ppp_ahdlc.c
Ignore the generated binaries and sparcv9 directory such that CVS
[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.1 2000/04/18 23:51:28 masputra Exp $
45  */
46
47 /*
48  * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
49  */
50 #include <sys/types.h>
51 #include <sys/param.h>
52 #include <sys/stream.h>
53 #include <sys/errno.h>
54
55 #ifdef SVR4
56 #include <sys/conf.h>
57 #include <sys/kmem.h>
58 #include <sys/cmn_err.h>
59 #include <sys/ddi.h>
60 #else
61 #include <sys/user.h>
62 #ifdef __osf__
63 #include <sys/cmn_err.h>
64 #endif
65 #endif /* SVR4 */
66
67 #include <net/ppp_defs.h>
68 #include <net/pppio.h>
69 #include "ppp_mod.h"
70
71 /*
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         freemsg(mp);
531         break;
532
533     case M_HANGUP:
534 #if defined(USE_MUTEX)
535         mutex_enter(&state->lock);
536 #endif /* USE_MUTEX */
537         if (state->rx_buf != 0) {
538             /* XXX would like to send this up for debugging */
539             freemsg(state->rx_buf);
540             state->rx_buf = 0;
541         }
542         state->flags = IFLUSH;
543 #if defined(USE_MUTEX)
544         mutex_exit(&state->lock);
545 #endif /* USE_MUTEX */
546         putnext(q, mp);
547         break;
548
549     default:
550         putnext(q, mp);
551     }
552     return 0;
553 }
554
555 /*
556  * Extract bit c from map m, to determine if c needs to be escaped
557  */
558 #define IN_TX_MAP(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
559
560 static void
561 ahdlc_encode(q, mp)
562     queue_t     *q;
563     mblk_t      *mp;
564 {
565     ahdlc_state_t       *state;
566     u_int32_t           *xaccm, loc_xaccm[8];
567     ushort_t            fcs;
568     size_t              outmp_len;
569     mblk_t              *outmp, *tmp;
570     uchar_t             *dp, fcs_val;
571     int                 is_lcp, code;
572 #if defined(SOL2)
573     clock_t             lbolt;
574 #endif /* SOL2 */
575
576     if (msgdsize(mp) < 4) {
577         return;
578     }
579
580     state = (ahdlc_state_t *)q->q_ptr;
581 #if defined(USE_MUTEX)
582     mutex_enter(&state->lock);
583 #endif /* USE_MUTEX */
584
585     /*
586      * Allocate an output buffer large enough to handle a case where all
587      * characters need to be escaped
588      */
589     outmp_len = (msgdsize(mp)    << 1) +                /* input block x 2 */
590                 (sizeof(fcs)     << 2) +                /* HDLC FCS x 4 */
591                 (sizeof(uchar_t) << 1);                 /* HDLC flags x 2 */
592
593     outmp = allocb(outmp_len, BPRI_MED);
594     if (outmp == NULL) {
595         state->stats.ppp_oerrors++;
596 #if defined(USE_MUTEX)
597         mutex_exit(&state->lock);
598 #endif /* USE_MUTEX */
599         putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
600         return;
601     }
602
603 #if defined(SOL2)
604     /*
605      * Check if our last transmit happenned within flag_time, using
606      * the system's LBOLT value in clock ticks
607      */
608     if (drv_getparm(LBOLT, &lbolt) != -1) {
609         if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
610             *outmp->b_wptr++ = PPP_FLAG;
611         } 
612         state->lbolt = lbolt;
613     } else {
614         *outmp->b_wptr++ = PPP_FLAG;
615     }
616 #else
617     /*
618      * If the driver below still has a message to process, skip the
619      * HDLC flag, otherwise, put one in the beginning
620      */
621     if (qsize(q->q_next) == 0) {
622         *outmp->b_wptr++ = PPP_FLAG;
623     }
624 #endif
625
626     /*
627      * All control characters must be escaped for LCP packets with code
628      * values between 1 (Conf-Req) and 7 (Code-Rej).
629      */
630     is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) && 
631               (MSG_BYTE(mp, 1) == PPP_UI) && 
632               (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
633               (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
634               LCP_USE_DFLT(mp));
635
636     xaccm = state->xaccm;
637     if (is_lcp) {
638         bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
639         loc_xaccm[0] = ~0;      /* force escape on 0x00 through 0x1f */
640         xaccm = loc_xaccm;
641     }
642
643     fcs = PPP_INITFCS;          /* Initial FCS is 0xffff */
644
645     /*
646      * Process this block and the rest (if any) attached to the this one
647      */
648     for (tmp = mp; tmp; tmp = tmp->b_cont) {
649         if (tmp->b_datap->db_type == M_DATA) {
650             for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
651                 fcs = PPP_FCS(fcs, *dp);
652                 if (IN_TX_MAP(*dp, xaccm)) {
653                     *outmp->b_wptr++ = PPP_ESCAPE;
654                     *outmp->b_wptr++ = *dp ^ PPP_TRANS;
655                 } else {
656                     *outmp->b_wptr++ = *dp;
657                 }
658             }
659         } else {
660             continue;   /* skip if db_type is something other than M_DATA */
661         }
662     }
663
664     /*
665      * Append the HDLC FCS, making sure that escaping is done on any
666      * necessary bytes
667      */
668     fcs_val = (fcs ^ 0xffff) & 0xff;
669     if (IN_TX_MAP(fcs_val, xaccm)) {
670         *outmp->b_wptr++ = PPP_ESCAPE;
671         *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
672     } else {
673         *outmp->b_wptr++ = fcs_val;
674     }
675
676     fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
677     if (IN_TX_MAP(fcs_val, xaccm)) {
678         *outmp->b_wptr++ = PPP_ESCAPE;
679         *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
680     } else {
681         *outmp->b_wptr++ = fcs_val;
682     }
683
684     /*
685      * And finally, append the HDLC flag, and send it away
686      */
687     *outmp->b_wptr++ = PPP_FLAG;
688
689     state->stats.ppp_obytes += msgdsize(outmp);
690     state->stats.ppp_opackets++;
691
692 #if defined(USE_MUTEX)
693     mutex_exit(&state->lock);
694 #endif /* USE_MUTEX */
695
696     putnext(q, outmp);
697     return;
698 }
699
700 /*
701  * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
702  */
703 #define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) < 0x20) && \
704                         (m) & (1 << (c)))
705
706
707 /*
708  * Process received characters.
709  */
710 static void
711 ahdlc_decode(q, mp)
712     queue_t *q;
713     mblk_t  *mp;
714 {
715     ahdlc_state_t   *state;
716     mblk_t          *om;
717     uchar_t         *dp;
718     ushort_t        fcs;
719 #if defined(SOL2)
720     mblk_t          *zmp;
721 #endif /* SOL2 */
722
723 #if defined(SOL2)
724     /*
725      * In case the driver (or something below) doesn't send
726      * data upstream in one message block, concatenate everything
727      */
728     if (!((mp->b_wptr - mp->b_rptr == msgdsize(mp)) && 
729          ((intpointer_t)mp->b_rptr % sizeof(intpointer_t) == 0))) {
730
731         zmp = msgpullup(mp, -1);
732         freemsg(mp);
733         mp = zmp;
734         if (mp == 0)
735             return; 
736     }
737 #endif /* SOL2 */
738
739     state = (ahdlc_state_t *) q->q_ptr;
740
741 #if defined(USE_MUTEX)
742     mutex_enter(&state->lock);
743 #endif /* USE_MUTEX */
744
745     state->stats.ppp_ibytes += msgdsize(mp);
746
747     for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) {
748
749         /*
750          * This should detect the lack of 8-bit communication channel
751          * which is necessary for PPP to work. In addition, it also
752          * checks on the parity.
753          */
754         if (*dp & 0x80)
755             state->flags |= RCV_B7_1;
756         else
757             state->flags |= RCV_B7_0;
758
759         if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
760             state->flags |= RCV_ODDP;
761         else
762             state->flags |= RCV_EVNP;
763
764         /*
765          * So we have a HDLC flag ...
766          */
767         if (*dp == PPP_FLAG) {
768
769             /*
770              * If we think that it marks the beginning of the frame,
771              * then continue to process the next octects
772              */
773             if ((state->flags & IFLUSH) ||
774                 (state->rx_buf == 0) ||
775                 (msgdsize(state->rx_buf) == 0)) {
776
777                 state->flags &= ~IFLUSH;
778                 continue;
779             }
780
781             /*
782              * We get here because the above condition isn't true,
783              * in which case the HDLC flag was there to mark the end
784              * of the frame (or so we think)
785              */
786             om = state->rx_buf;
787
788             if (state->infcs == PPP_GOODFCS) {
789                 state->stats.ppp_ipackets++;
790                 adjmsg(om, -PPP_FCSLEN);
791                 putnext(q, om);
792             } else {
793                 DPRINT2("ppp%d: bad fcs (len=%d)\n",
794                     state->unit, msgdsize(state->rx_buf));
795                 freemsg(state->rx_buf);
796                 state->flags &= ~(IFLUSH | ESCAPED);
797                 state->stats.ppp_ierrors++;
798                 putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
799             }
800
801             state->rx_buf = 0;
802             continue;
803         }
804
805         if (state->flags & IFLUSH) {
806             continue;
807         }
808
809         /*
810          * Allocate a receive buffer, large enough to store a frame (after
811          * un-escaping) of at least 1500 octets. If MRU is negotiated to
812          * be more than the default, then allocate that much. In addition,
813          * we add an extra 32-bytes for a fudge factor
814          */ 
815         if (state->rx_buf == 0) {
816             state->rx_buf_size  = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
817             state->rx_buf_size += (sizeof(u_int32_t) << 3);
818             state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
819
820             /*
821              * If allocation fails, try again on the next frame
822              */
823             if (state->rx_buf == 0) {
824                 state->flags |= IFLUSH;
825                 continue;
826             }
827             state->flags &= ~(IFLUSH | ESCAPED);
828             state->infcs  = PPP_INITFCS;
829         }
830
831         if (*dp == PPP_ESCAPE) {
832             state->flags |= ESCAPED;
833             continue;
834         }
835
836         /*
837          * Make sure we un-escape the necessary characters, as well as the
838          * ones in our receive async control character map
839          */
840         if (state->flags & ESCAPED) {
841             *dp ^= PPP_TRANS;
842             state->flags &= ~ESCAPED;
843         } else if (IN_RX_MAP(*dp, state->raccm)) 
844             continue;
845
846         /*
847          * Unless the peer lied to us about the negotiated MRU, we should
848          * never get a frame which is too long. If it happens, toss it away
849          * and grab the next incoming one
850          */
851         if (msgdsize(state->rx_buf) < state->rx_buf_size) {
852             state->infcs = PPP_FCS(state->infcs, *dp);
853             *state->rx_buf->b_wptr++ = *dp;
854         } else {
855             DPRINT2("ppp%d: frame too long (%d)\n",
856                 state->unit, msgdsize(state->rx_buf));
857             freemsg(state->rx_buf);
858             state->rx_buf     = 0;
859             state->flags     |= IFLUSH;
860         }
861     }
862
863 #if defined(USE_MUTEX)
864     mutex_exit(&state->lock);
865 #endif /* USE_MUTEX */
866 }
867
868 static int
869 msg_byte(mp, i)
870     mblk_t *mp;
871     unsigned int i;
872 {
873     while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
874         mp = mp->b_cont;
875     if (mp == 0)
876         return -1;
877     return mp->b_rptr[i];
878 }