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