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