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