]> git.ozlabs.org Git - ppp.git/blob - modules/ppp_ahdlc.c
1828fe1e96fb40a1f20a48eb0267975aad083178
[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.11 1999/09/15 23:49:05 masputra 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     ahdlc_state_t *state;
347
348     state = (ahdlc_state_t *) q->q_ptr;
349     if (state == 0) {
350         DPRINT("state == 0 in ahdlc_rput\n");
351         freemsg(mp);
352         return 0;
353     }
354
355     switch (mp->b_datap->db_type) {
356     case M_DATA:
357         unstuff_chars(q, mp);
358         freemsg(mp);
359         break;
360
361     case M_HANGUP:
362         if (state->cur_frame != 0) {
363             /* XXX would like to send this up for debugging */
364             freemsg(state->cur_frame);
365             state->cur_frame = 0;
366             state->cur_blk = 0;
367         }
368         state->inlen = 0;
369         state->flags = IFLUSH;
370         putnext(q, mp);
371         break;
372
373     default:
374         putnext(q, mp);
375     }
376     return 0;
377 }
378
379 /* Extract bit c from map m, to determine if c needs to be escaped. */
380 #define ESCAPE(c, m)    ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
381
382 static void
383 stuff_frame(q, mp)
384     queue_t *q;
385     mblk_t *mp;
386 {
387     ahdlc_state_t *state;
388     int ilen, olen, c, extra, code;
389     mblk_t *omsg, *op, *np;
390     uchar_t *sp, *sp0, *dp, *dp0, *spend;
391     ushort_t fcs;
392     u_int32_t *xaccm, lcp_xaccm[8];
393
394     state = (ahdlc_state_t *) q->q_ptr;
395     ilen = msgdsize(mp);
396
397     /*
398      * We estimate the length of the output packet as
399      * 1.25 * input length + 16 (for initial flag, FCS, final flag, slop).
400      */
401     olen = ilen + (ilen >> 2) + 16;
402     if (olen > OFRAME_BSIZE)
403         olen = OFRAME_BSIZE;
404     omsg = op = allocb(olen, BPRI_MED);
405     if (omsg == 0)
406         goto bomb;
407
408     /*
409      * Put in an initial flag, unless the serial driver currently has
410      * packets still to be transmitted in its queue.
411      */
412     dp = op->b_wptr;
413     if (qsize(q->q_next) == 0) {
414         *dp++ = PPP_FLAG;
415         --olen;
416     }
417
418     /*
419      * For LCP packets with code values between 1 and 7 (Conf-Req
420      * to Code-Rej), we must escape all control characters.
421      */
422     xaccm = state->xaccm;
423     if (MSG_BYTE(mp, 0) == PPP_ALLSTATIONS
424         && MSG_BYTE(mp, 1) == PPP_UI
425         && MSG_BYTE(mp, 2) == (PPP_LCP >> 8)
426         && MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)
427         && LCP_USE_DFLT(mp)) {
428         bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, sizeof(lcp_xaccm));
429         lcp_xaccm[0] = ~0;
430         xaccm = lcp_xaccm;
431     }
432
433     sp = mp->b_rptr;
434     fcs = PPP_INITFCS;
435     for (;;) {
436         spend = mp->b_wptr;
437         extra = sp + olen - spend;
438         if (extra < 0) {
439             spend = sp + olen;
440             extra = 0;
441         }
442         /*
443          * We can safely process the input up to `spend'
444          * without overrunning the output, provided we don't
445          * hit more than `extra' characters which need to be escaped.
446          */
447         sp0 = sp;
448         dp0 = dp;
449         while (sp < spend) {
450             c = *sp;
451             if (ESCAPE(c, xaccm)) {
452                 if (extra > 0)
453                     --extra;
454                 else if (sp < spend - 1)
455                     --spend;
456                 else
457                     break;
458                 fcs = PPP_FCS(fcs, c);
459                 *dp++ = PPP_ESCAPE;
460                 c ^= PPP_TRANS;
461             } else
462                 fcs = PPP_FCS(fcs, c);
463             *dp++ = c;
464             ++sp;
465         }
466         ilen -= sp - sp0;
467         olen -= dp - dp0;
468
469         /*
470          * At this point, we have emptied an input block
471          * and/or filled an output block.
472          */
473         if (sp >= mp->b_wptr) {
474             /*
475              * We've emptied an input block.  Advance to the next.
476              */
477             mp = mp->b_cont;
478             if (mp == 0)
479                 break;          /* all done */
480             sp = mp->b_rptr;
481         }
482         if (olen < 2) {
483             /*
484              * The output block is full.  Allocate a new one.
485              */
486             op->b_wptr = dp;
487             olen = 2 * ilen + 5;
488             if (olen > OFRAME_BSIZE)
489                 olen = OFRAME_BSIZE;
490             np = allocb(olen, BPRI_MED);
491             if (np == 0)
492                 goto bomb;
493             op->b_cont = np;
494             op = np;
495             dp = op->b_wptr;
496         }
497     }
498
499     /*
500      * Append the FCS and closing flag.
501      * This could require up to 5 characters.
502      */
503     if (olen < 5) {
504         /* Sigh.  Need another block. */
505         op->b_wptr = dp;
506         np = allocb(5, BPRI_MED);
507         if (np == 0)
508             goto bomb;
509         op->b_cont = np;
510         op = np;
511         dp = op->b_wptr;
512     }
513     c = ~fcs & 0xff;
514     if (ESCAPE(c, xaccm)) {
515         *dp++ = PPP_ESCAPE;
516         c ^= PPP_TRANS;
517     }
518     *dp++ = c;
519     c = (~fcs >> 8) & 0xff;
520     if (ESCAPE(c, xaccm)) {
521         *dp++ = PPP_ESCAPE;
522         c ^= PPP_TRANS;
523     }
524     *dp++ = c;
525     *dp++ = PPP_FLAG;
526     op->b_wptr = dp;
527
528     /*
529      * Update statistics.
530      */
531     state->stats.ppp_obytes += msgdsize(omsg);
532     state->stats.ppp_opackets++;
533
534     /*
535      * Send it on.
536      */
537     putnext(q, omsg);
538     return;
539
540  bomb:
541     if (omsg != 0)
542         freemsg(omsg);
543     state->stats.ppp_oerrors++;
544     putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
545 }
546
547 #define UPDATE_FLAGS(c) {                               \
548     if ((c) & 0x80)                                     \
549         state->flags |= RCV_B7_1;                       \
550     else                                                \
551         state->flags |= RCV_B7_0;                       \
552     if (0x6996 & (1 << ((((c) >> 4) ^ (c)) & 0xf)))     \
553         state->flags |= RCV_ODDP;                       \
554     else                                                \
555         state->flags |= RCV_EVNP;                       \
556 }
557
558 /*
559  * Process received characters.
560  */
561 static void
562 unstuff_chars(q, mp)
563     queue_t *q;
564     mblk_t *mp;
565 {
566     ahdlc_state_t *state;
567     mblk_t *om;
568     uchar_t *cp, *cpend, *dp, *dp0;
569     int c, len, extra;
570     ushort_t fcs;
571
572     state = (ahdlc_state_t *) q->q_ptr;
573     state->stats.ppp_ibytes += msgdsize(mp);
574     cp = mp->b_rptr;
575     for (;;) {
576         /*
577          * Advance to next input block if necessary.
578          */
579         if (cp >= mp->b_wptr) {
580             mp = mp->b_cont;
581             if (mp == 0)
582                 break;
583             cp = mp->b_rptr;
584             continue;
585         }
586
587         if ((state->flags & (IFLUSH|ESCAPED)) == 0
588             && state->inlen > 0 && (om = state->cur_blk) != 0) {
589             /*
590              * Process bulk chars as quickly as possible.
591              */
592             dp = om->b_wptr;
593             len = om->b_datap->db_lim - dp; /* max # output bytes */
594             extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
595             if (extra < 0) {
596                 len += extra;               /* we'll run out of input first */
597                 extra = 0;
598             }
599             cpend = cp + len;
600             dp0 = dp;
601             fcs = state->infcs;
602             while (cp < cpend) {
603                 c = *cp;
604                 if (c == PPP_FLAG)
605                     break;
606                 ++cp;
607                 UPDATE_FLAGS(c);
608                 if (c == PPP_ESCAPE) {
609                     if (extra > 0) {
610                         --extra;
611                         ++cpend;
612                     }
613                     if (cp >= cpend || (c = *cp) == PPP_FLAG) {
614                         state->flags |= ESCAPED;
615                         break;
616                     }
617                     ++cp;
618                     UPDATE_FLAGS(c);
619                     c ^= PPP_TRANS;
620                 }
621                 *dp++ = c;
622                 fcs = PPP_FCS(fcs, c);
623             }
624             state->inlen += dp - dp0;
625             state->infcs = fcs;
626             om->b_wptr = dp;
627             if (cp >= mp->b_wptr)
628                 continue;       /* advance to the next mblk */
629         }
630
631         c = *cp++;
632         UPDATE_FLAGS(c);
633         if (c == PPP_FLAG) {
634             /*
635              * End of a frame.
636              * If the ESCAPE flag is set, the frame ended with
637              * the frame abort sequence "}~".
638              */
639             om = state->cur_frame;
640             len = state->inlen;
641             state->cur_frame = 0;
642             state->inlen = 0;
643             if (len == 0 && (state->flags & IFLUSH) == 0)
644                 continue;
645             state->stats.ppp_ipackets++;
646             if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0
647                 && len > PPP_FCSLEN) {
648                 if (state->infcs == PPP_GOODFCS) {
649                     adjmsg(om, -PPP_FCSLEN);    /* chop off fcs */
650                     putnext(q, om);             /* bombs away! */
651                     continue;
652                 }
653                 DPRINT2("ppp%d: bad fcs (len=%d)\n", state->unit, len);
654             }
655             if (om != 0)
656                 freemsg(om);
657             state->flags &= ~(IFLUSH|ESCAPED);
658             state->stats.ppp_ierrors++;
659             putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
660             continue;
661         }
662
663         if (state->flags & IFLUSH)
664             continue;
665         if (state->flags & ESCAPED) {
666             c ^= PPP_TRANS;
667             state->flags &= ~ESCAPED;
668         } else if (c == PPP_ESCAPE) {
669             state->flags |= ESCAPED;
670             continue;
671         }
672         if (state->inlen == 0) {
673             /*
674              * First byte of the frame: allocate the first message block.
675              */
676             om = allocb(IFRAME_BSIZE, BPRI_MED);
677             if (om == 0) {
678                 state->flags |= IFLUSH;
679                 continue;
680             }
681             state->cur_frame = om;
682             state->cur_blk = om;
683             state->infcs = PPP_INITFCS;
684         } else {
685             om = state->cur_blk;
686             if (om->b_wptr >= om->b_datap->db_lim) {
687                 /*
688                  * Current message block is full.  Allocate another one,
689                  * unless we have run out of MRU.
690                  */
691                 if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
692                     state->flags |= IFLUSH;
693                     DPRINT2("ppp%d: frame too long (%d)\n",
694                             state->unit, state->inlen);
695                     continue;
696                 }
697                 om = allocb(IFRAME_BSIZE, BPRI_MED);
698                 if (om == 0) {
699                     state->flags |= IFLUSH;
700                     continue;
701                 }
702                 state->cur_blk->b_cont = om;
703                 state->cur_blk = om;
704             }
705         }
706
707         if (state->inlen == 0) {
708             /*
709              * We don't do address/control & protocol decompression here,
710              * but we try to put the first byte at an offset such that
711              * the info field starts on a word boundary.  The code here
712              * will do this except for packets with protocol compression
713              * but not address/control compression.
714              */
715             if (c != PPP_ALLSTATIONS) {
716                 om->b_wptr += 2;
717                 if (c & 1)
718                     ++om->b_wptr;
719                 om->b_rptr = om->b_wptr;
720             }
721         }
722
723         *om->b_wptr++ = c;
724         ++state->inlen;
725         state->infcs = PPP_FCS(state->infcs, c);
726     }
727 }
728
729 static int
730 msg_byte(mp, i)
731     mblk_t *mp;
732     unsigned int i;
733 {
734     while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
735         mp = mp->b_cont;
736     if (mp == 0)
737         return -1;
738     return mp->b_rptr[i];
739 }