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