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