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