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