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