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)
101typedef long                    intpointer_t;
102typedef unsigned long           uintpointer_t;
103#else
104typedef int                     intpointer_t;
105typedef unsigned int            uintpointer_t;
106#endif
107
108MOD_OPEN_DECL(ahdlc_open);
109MOD_CLOSE_DECL(ahdlc_close);
110static int ahdlc_wput __P((queue_t *, mblk_t *));
111static int ahdlc_rput __P((queue_t *, mblk_t *));
112static void ahdlc_encode __P((queue_t *, mblk_t *));
113static void ahdlc_decode __P((queue_t *, mblk_t *));
114static 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 */
139static struct module_info minfo = {
140    0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
141};
142
143static struct qinit rinit = {
144    ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
145};
146
147static struct qinit winit = {
148    ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
149};
150
151#if defined(SVR4) && !defined(SOL2)
152int phdldevflag = 0;
153#define ppp_ahdlcinfo phdlinfo
154#endif /* defined(SVR4) && !defined(SOL2) */
155
156struct 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)
167int ppp_ahdlc_count = 0;	    /* open counter */
168#endif /* SUNOS4 */
169
170/*
171 * Per-stream state structure
172 */
173typedef 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 */
207static 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
242static 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 */
251MOD_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 */
305MOD_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 */
347static int
348ahdlc_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 */
528static int
529ahdlc_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
574static void
575ahdlc_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 */
724static void
725ahdlc_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
863static int
864msg_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}
874