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