not used any more
[ppp.git] / modules / ppp_ahdlc.c
1 /*
2  * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
3  *
4  * Copyright (c) 1994 The Australian National University.
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation is hereby granted, provided that the above copyright
9  * notice appears in all copies.  This software is provided without any
10  * warranty, express or implied. The Australian National University
11  * makes no representations about the suitability of this software for
12  * any purpose.
13  *
14  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
18  * OF SUCH DAMAGE.
19  *
20  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
25  * OR MODIFICATIONS.
26  *
27  * $Id: ppp_ahdlc.c,v 1.4 1996/09/14 05:19:18 paulus Exp $
28  */
29
30 /*
31  * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
32  */
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/stream.h>
36 #include <sys/errno.h>
37
38 #ifdef SVR4
39 #include <sys/conf.h>
40 #include <sys/kmem.h>
41 #include <sys/cmn_err.h>
42 #include <sys/ddi.h>
43 #else
44 #include <sys/user.h>
45 #endif /* SVR4 */
46
47 #include <net/ppp_defs.h>
48 #include <net/pppio.h>
49 #include "ppp_mod.h"
50
51 #define IFRAME_BSIZE    512     /* Block size to allocate for input */
52 #define OFRAME_BSIZE    4096    /* Don't allocb more than this for output */
53
54 MOD_OPEN_DECL(ahdlc_open);
55 MOD_CLOSE_DECL(ahdlc_close);
56 static int ahdlc_wput __P((queue_t *, mblk_t *));
57 static int ahdlc_rput __P((queue_t *, mblk_t *));
58 static void stuff_frame __P((queue_t *, mblk_t *));
59 static void unstuff_chars __P((queue_t *, mblk_t *));
60 static int msg_byte __P((mblk_t *, unsigned int));
61
62 /* Extract byte i of message mp. */
63 #define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
64                          msg_byte((mp), (i)))
65
66 /* Is this LCP packet one we have to transmit using LCP defaults? */
67 #define LCP_USE_DFLT(mp)        (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
68
69 #define PPP_AHDL_ID 0x7d23
70 static struct module_info minfo = {
71     PPP_AHDL_ID, "ppp_ahdl", 0, INFPSZ, 4096, 128
72 };
73
74 static struct qinit rinit = {
75     ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
76 };
77
78 static struct qinit winit = {
79     ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
80 };
81
82 #if defined(SVR4) && !defined(SOL2)
83 int phdldevflag = 0;
84 #define ppp_ahdlcinfo phdlinfo
85 #endif
86 struct streamtab ppp_ahdlcinfo = {
87     &rinit, &winit, NULL, NULL
88 };
89
90 int ppp_ahdlc_count;
91
92 typedef struct ahdlc_state {
93     int flags;
94     mblk_t *cur_frame;
95     mblk_t *cur_blk;
96     int inlen;
97     ushort infcs;
98     u_int32_t xaccm[8];
99     u_int32_t raccm;
100     int mtu;
101     int mru;
102     int unit;
103     struct pppstat stats;
104 } ahdlc_state_t;
105
106 /* Values for flags */
107 #define ESCAPED         0x100   /* last saw escape char on input */
108 #define IFLUSH          0x200   /* flushing input due to error */
109
110 /* RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. */
111 #define RCV_FLAGS       (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
112
113 /*
114  * FCS lookup table as calculated by genfcstab.
115  */
116 static u_short fcstab[256] = {
117         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
118         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
119         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
120         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
121         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
122         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
123         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
124         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
125         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
126         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
127         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
128         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
129         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
130         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
131         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
132         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
133         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
134         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
135         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
136         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
137         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
138         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
139         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
140         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
141         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
142         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
143         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
144         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
145         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
146         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
147         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
148         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
149 };
150
151 /*
152  * STREAMS module entry points.
153  */
154 MOD_OPEN(ahdlc_open)
155 {
156     ahdlc_state_t *sp;
157
158     if (q->q_ptr == 0) {
159         sp = (ahdlc_state_t *) ALLOC_SLEEP(sizeof(ahdlc_state_t));
160         if (sp == 0)
161             OPEN_ERROR(ENOSR);
162         bzero((caddr_t) sp, sizeof(ahdlc_state_t));
163         q->q_ptr = (caddr_t) sp;
164         WR(q)->q_ptr = (caddr_t) sp;
165         sp->xaccm[0] = ~0;
166         sp->xaccm[3] = 0x60000000;
167         sp->mru = 1500;
168         ++ppp_ahdlc_count;
169         qprocson(q);
170     }
171     return 0;
172 }
173
174 MOD_CLOSE(ahdlc_close)
175 {
176     ahdlc_state_t *state;
177
178     qprocsoff(q);
179     if (q->q_ptr != 0) {
180         state = (ahdlc_state_t *) q->q_ptr;
181         if (state->cur_frame != 0) {
182             freemsg(state->cur_frame);
183             state->cur_frame = 0;
184         }
185         FREE(q->q_ptr, sizeof(ahdlc_state_t));
186         --ppp_ahdlc_count;
187     }
188     return 0;
189 }
190
191 static int
192 ahdlc_wput(q, mp)
193     queue_t *q;
194     mblk_t *mp;
195 {
196     ahdlc_state_t *state;
197     struct iocblk *iop;
198     int error;
199     mblk_t *np;
200     struct ppp_stats *psp;
201
202     state = (ahdlc_state_t *) q->q_ptr;
203     switch (mp->b_datap->db_type) {
204     case M_DATA:
205         /*
206          * A data packet - do character-stuffing and FCS, and
207          * send it onwards.
208          */
209         stuff_frame(q, mp);
210         freemsg(mp);
211         break;
212
213     case M_IOCTL:
214         iop = (struct iocblk *) mp->b_rptr;
215         error = EINVAL;
216         switch (iop->ioc_cmd) {
217         case PPPIO_XACCM:
218             if (iop->ioc_count < sizeof(u_int32_t)
219                 || iop->ioc_count > sizeof(ext_accm))
220                 break;
221             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
222                   iop->ioc_count);
223             state->xaccm[2] &= ~0x40000000;     /* don't escape 0x5e */
224             state->xaccm[3] |= 0x60000000;      /* do escape 0x7d, 0x7e */
225             iop->ioc_count = 0;
226             error = 0;
227             break;
228
229         case PPPIO_RACCM:
230             if (iop->ioc_count != sizeof(u_int32_t))
231                 break;
232             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
233                   sizeof(u_int32_t));
234             iop->ioc_count = 0;
235             error = 0;
236             break;
237
238         case PPPIO_GCLEAN:
239             np = allocb(sizeof(int), BPRI_HI);
240             if (np == 0) {
241                 error = ENOSR;
242                 break;
243             }
244             if (mp->b_cont != 0)
245                 freemsg(mp->b_cont);
246             mp->b_cont = np;
247             *(int *)np->b_wptr = state->flags & RCV_FLAGS;
248             np->b_wptr += sizeof(int);
249             iop->ioc_count = sizeof(int);
250             error = 0;
251             break;
252
253         case PPPIO_GETSTAT:
254             np = allocb(sizeof(struct ppp_stats), BPRI_HI);
255             if (np == 0) {
256                 error = ENOSR;
257                 break;
258             }
259             if (mp->b_cont != 0)
260                 freemsg(mp->b_cont);
261             mp->b_cont = np;
262             psp = (struct ppp_stats *) np->b_wptr;
263             np->b_wptr += sizeof(struct ppp_stats);
264             bzero((caddr_t)psp, sizeof(struct ppp_stats));
265             psp->p = state->stats;
266             iop->ioc_count = sizeof(struct ppp_stats);
267             error = 0;
268             break;
269
270         case PPPIO_LASTMOD:
271             /* we knew this anyway */
272             error = 0;
273             break;
274
275         default:
276             error = -1;
277             break;
278         }
279
280         if (error < 0)
281             putnext(q, mp);
282         else if (error == 0) {
283             mp->b_datap->db_type = M_IOCACK;
284             qreply(q, mp);
285         } else {
286             mp->b_datap->db_type = M_IOCNAK;
287             iop->ioc_count = 0;
288             iop->ioc_error = error;
289             qreply(q, mp);
290         }
291         break;
292
293     case M_CTL:
294         switch (*mp->b_rptr) {
295         case PPPCTL_MTU:
296             state->mtu = ((unsigned short *)mp->b_rptr)[1];
297             freemsg(mp);
298             break;
299         case PPPCTL_MRU:
300             state->mru = ((unsigned short *)mp->b_rptr)[1];
301             freemsg(mp);
302             break;
303         case PPPCTL_UNIT:
304             state->unit = mp->b_rptr[1];
305             break;
306         default:
307             putnext(q, mp);
308         }
309         break;
310
311     default:
312         putnext(q, mp);
313     }
314     return 0;
315 }
316
317 static int
318 ahdlc_rput(q, mp)
319     queue_t *q;
320     mblk_t *mp;
321 {
322     mblk_t *np;
323     uchar_t *cp;
324     ahdlc_state_t *state;
325
326     switch (mp->b_datap->db_type) {
327     case M_DATA:
328         unstuff_chars(q, mp);
329         freemsg(mp);
330         break;
331
332     case M_HANGUP:
333         state = (ahdlc_state_t *) q->q_ptr;
334         if (state->cur_frame != 0) {
335             /* XXX would like to send this up for debugging */
336             freemsg(state->cur_frame);
337             state->cur_frame = 0;
338             state->cur_blk = 0;
339         }
340         state->inlen = 0;
341         state->flags = IFLUSH;
342         putnext(q, mp);
343         break;
344
345     default:
346         putnext(q, mp);
347     }
348     return 0;
349 }
350
351 /* Extract bit c from map m, to determine if c needs to be escaped. */
352 #define ESCAPE(c, m)    ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
353
354 static void
355 stuff_frame(q, mp)
356     queue_t *q;
357     mblk_t *mp;
358 {
359     ahdlc_state_t *state;
360     int ilen, olen, c, extra, i, code;
361     mblk_t *omsg, *op, *np;
362     uchar_t *sp, *sp0, *dp, *dp0, *spend;
363     ushort_t fcs;
364     u_int32_t *xaccm, lcp_xaccm[8];
365     static uchar_t lcphdr[PPP_HDRLEN] = { 0xff, 0x03, 0xc0, 0x21 };
366     uchar_t ppphdr[PPP_HDRLEN];
367
368     state = (ahdlc_state_t *) q->q_ptr;
369     ilen = msgdsize(mp);
370
371     /*
372      * We estimate the length of the output packet as
373      * 1.25 * input length + 16 (for initial flag, FCS, final flag, slop).
374      */
375     olen = ilen + (ilen >> 2) + 16;
376     if (olen > OFRAME_BSIZE)
377         olen = OFRAME_BSIZE;
378     omsg = op = allocb(olen, BPRI_MED);
379     if (omsg == 0)
380         goto bomb;
381
382     /*
383      * Put in an initial flag for now.  We'll remove it later
384      * if we decide we don't need it.
385      */
386     dp = op->b_wptr;
387     *dp++ = PPP_FLAG;
388     --olen;
389
390     /*
391      * For LCP packets with code values between 1 and 7 (Conf-Req
392      * to Code-Rej), we must escape all control characters.
393      */
394     xaccm = state->xaccm;
395     if (MSG_BYTE(mp, 0) == PPP_ALLSTATIONS
396         && MSG_BYTE(mp, 1) == PPP_UI
397         && MSG_BYTE(mp, 2) == (PPP_LCP >> 8)
398         && MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)
399         && LCP_USE_DFLT(mp)) {
400         bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, sizeof(lcp_xaccm));
401         lcp_xaccm[0] = ~0;
402         xaccm = lcp_xaccm;
403     }
404
405     sp = mp->b_rptr;
406     fcs = PPP_INITFCS;
407     for (;;) {
408         spend = mp->b_wptr;
409         extra = sp + olen - spend;
410         if (extra < 0) {
411             spend = sp + olen;
412             extra = 0;
413         }
414         /*
415          * We can safely process the input up to `spend'
416          * without overrunning the output, provided we don't
417          * hit more than `extra' characters which need to be escaped.
418          */
419         sp0 = sp;
420         dp0 = dp;
421         while (sp < spend) {
422             c = *sp;
423             if (ESCAPE(c, xaccm)) {
424                 if (extra > 0)
425                     --extra;
426                 else if (sp < spend - 1)
427                     --spend;
428                 else
429                     break;
430                 fcs = PPP_FCS(fcs, c);
431                 *dp++ = PPP_ESCAPE;
432                 c ^= PPP_TRANS;
433             } else
434                 fcs = PPP_FCS(fcs, c);
435             *dp++ = c;
436             ++sp;
437         }
438         ilen -= sp - sp0;
439         olen -= dp - dp0;
440
441         /*
442          * At this point, we have emptied an input block
443          * and/or filled an output block.
444          */
445         if (sp >= mp->b_wptr) {
446             /*
447              * We've emptied an input block.  Advance to the next.
448              */
449             mp = mp->b_cont;
450             if (mp == 0)
451                 break;          /* all done */
452             sp = mp->b_rptr;
453         }
454         if (olen < 2) {
455             /*
456              * The output block is full.  Allocate a new one.
457              */
458             op->b_wptr = dp;
459             olen = 2 * ilen + 5;
460             if (olen > OFRAME_BSIZE)
461                 olen = OFRAME_BSIZE;
462             np = allocb(olen, BPRI_MED);
463             if (np == 0)
464                 goto bomb;
465             op->b_cont = np;
466             op = np;
467             dp = op->b_wptr;
468         }
469     }
470
471     /*
472      * Append the FCS and closing flag.
473      * This could require up to 5 characters.
474      */
475     if (olen < 5) {
476         /* Sigh.  Need another block. */
477         op->b_wptr = dp;
478         np = allocb(5, BPRI_MED);
479         if (np == 0)
480             goto bomb;
481         op->b_cont = np;
482         op = np;
483         dp = op->b_wptr;
484     }
485     c = ~fcs & 0xff;
486     if (ESCAPE(c, xaccm)) {
487         *dp++ = PPP_ESCAPE;
488         c ^= PPP_TRANS;
489     }
490     *dp++ = c;
491     c = (~fcs >> 8) & 0xff;
492     if (ESCAPE(c, xaccm)) {
493         *dp++ = PPP_ESCAPE;
494         c ^= PPP_TRANS;
495     }
496     *dp++ = c;
497     *dp++ = PPP_FLAG;
498     op->b_wptr = dp;
499
500     /*
501      * Remove the initial flag, if possible.
502      */
503     if (qsize(q->q_next) > 0)
504         ++omsg->b_rptr;
505
506     /*
507      * Update statistics.
508      */
509     state->stats.ppp_obytes += msgdsize(omsg);
510     state->stats.ppp_opackets++;
511
512     /*
513      * Send it on.
514      */
515     putnext(q, omsg);
516     return;
517
518  bomb:
519     if (omsg != 0)
520         freemsg(omsg);
521     state->stats.ppp_oerrors++;
522     putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
523 }
524
525 #define UPDATE_FLAGS(c) {                               \
526     if ((c) & 0x80)                                     \
527         state->flags |= RCV_B7_1;                       \
528     else                                                \
529         state->flags |= RCV_B7_0;                       \
530     if (0x6996 & (1 << ((((c) >> 4) ^ (c)) & 0xf)))     \
531         state->flags |= RCV_ODDP;                       \
532     else                                                \
533         state->flags |= RCV_EVNP;                       \
534 }
535
536 /*
537  * Process received characters.
538  */
539 static void
540 unstuff_chars(q, mp)
541     queue_t *q;
542     mblk_t *mp;
543 {
544     ahdlc_state_t *state;
545     mblk_t *om;
546     uchar_t *cp, *cpend, *dp, *dp0;
547     int c, len, extra, offset;
548     ushort_t fcs;
549
550     state = (ahdlc_state_t *) q->q_ptr;
551     state->stats.ppp_ibytes += msgdsize(mp);
552     cp = mp->b_rptr;
553     for (;;) {
554         /*
555          * Advance to next input block if necessary.
556          */
557         if (cp >= mp->b_wptr) {
558             mp = mp->b_cont;
559             if (mp == 0)
560                 break;
561             cp = mp->b_rptr;
562             continue;
563         }
564
565         if ((state->flags & (IFLUSH|ESCAPED)) == 0
566             && state->inlen > 0 && (om = state->cur_blk) != 0) {
567             /*
568              * Process bulk chars as quickly as possible.
569              */
570             dp = om->b_wptr;
571             len = om->b_datap->db_lim - dp; /* max # output bytes */
572             extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
573             if (extra < 0) {
574                 len += extra;               /* we'll run out of input first */
575                 extra = 0;
576             }
577             cpend = cp + len;
578             dp0 = dp;
579             fcs = state->infcs;
580             while (cp < cpend) {
581                 c = *cp;
582                 if (c == PPP_FLAG)
583                     break;
584                 ++cp;
585                 UPDATE_FLAGS(c);
586                 if (c == PPP_ESCAPE) {
587                     if (extra > 0) {
588                         --extra;
589                         ++cpend;
590                     }
591                     if (cp >= cpend || (c = *cp) == PPP_FLAG) {
592                         state->flags |= ESCAPED;
593                         break;
594                     }
595                     ++cp;
596                     UPDATE_FLAGS(c);
597                     c ^= PPP_TRANS;
598                 }
599                 *dp++ = c;
600                 fcs = PPP_FCS(fcs, c);
601             }
602             state->inlen += dp - dp0;
603             state->infcs = fcs;
604             om->b_wptr = dp;
605             if (cp >= mp->b_wptr)
606                 continue;       /* advance to the next mblk */
607         }
608
609         c = *cp++;
610         UPDATE_FLAGS(c);
611         if (c == PPP_FLAG) {
612             /*
613              * End of a frame.
614              * If the ESCAPE flag is set, the frame ended with
615              * the frame abort sequence "}~".
616              */
617             om = state->cur_frame;
618             len = state->inlen;
619             state->cur_frame = 0;
620             state->inlen = 0;
621             if (len == 0 && (state->flags & IFLUSH) == 0)
622                 continue;
623             state->stats.ppp_ipackets++;
624             if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0
625                 && len > PPP_FCSLEN) {
626                 if (state->infcs == PPP_GOODFCS) {
627                     adjmsg(om, -PPP_FCSLEN);    /* chop off fcs */
628                     putnext(q, om);             /* bombs away! */
629                     continue;
630                 }
631                 DPRINT2("ppp%d: bad fcs (len=%d)\n", state->unit, len);
632             }
633             if (om != 0)
634                 freemsg(om);
635             state->flags &= ~(IFLUSH|ESCAPED);
636             state->stats.ppp_ierrors++;
637             putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
638             continue;
639         }
640
641         if (state->flags & IFLUSH)
642             continue;
643         if (state->flags & ESCAPED) {
644             c ^= PPP_TRANS;
645             state->flags &= ~ESCAPED;
646         } else if (c == PPP_ESCAPE) {
647             state->flags |= ESCAPED;
648             continue;
649         }
650         if (state->inlen == 0) {
651             /*
652              * First byte of the frame: allocate the first message block.
653              */
654             om = allocb(IFRAME_BSIZE, BPRI_MED);
655             if (om == 0) {
656                 state->flags |= IFLUSH;
657                 continue;
658             }
659             state->cur_frame = om;
660             state->cur_blk = om;
661             state->infcs = PPP_INITFCS;
662         } else {
663             om = state->cur_blk;
664             if (om->b_wptr >= om->b_datap->db_lim) {
665                 /*
666                  * Current message block is full.  Allocate another one,
667                  * unless we have run out of MRU.
668                  */
669                 if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
670                     state->flags |= IFLUSH;
671                     DPRINT2("ppp%d: frame too long (%d)\n",
672                             state->unit, state->inlen);
673                     continue;
674                 }
675                 om = allocb(IFRAME_BSIZE, BPRI_MED);
676                 if (om == 0) {
677                     state->flags |= IFLUSH;
678                     continue;
679                 }
680                 state->cur_blk->b_cont = om;
681                 state->cur_blk = om;
682             }
683         }
684
685         if (state->inlen == 0) {
686             /*
687              * We don't do address/control & protocol decompression here,
688              * but we try to put the first byte at an offset such that
689              * the info field starts on a word boundary.  The code here
690              * will do this except for packets with protocol compression
691              * but not address/control compression.
692              */
693             if (c != PPP_ALLSTATIONS) {
694                 om->b_wptr += 2;
695                 if (c & 1)
696                     ++om->b_wptr;
697                 om->b_rptr = om->b_wptr;
698             }
699         }
700
701         *om->b_wptr++ = c;
702         ++state->inlen;
703         state->infcs = PPP_FCS(state->infcs, c);
704     }
705 }
706
707 static int
708 msg_byte(mp, i)
709     mblk_t *mp;
710     unsigned int i;
711 {
712     while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
713         mp = mp->b_cont;
714     if (mp == 0)
715         return -1;
716     return mp->b_rptr[i];
717 }