]> git.ozlabs.org Git - ppp.git/blob - modules/ppp_ahdlc.c
added hide-password option
[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.9 1999/02/26 10:52:07 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 typedef struct ahdlc_state {
98     int flags;
99     mblk_t *cur_frame;
100     mblk_t *cur_blk;
101     int inlen;
102     ushort infcs;
103     u_int32_t xaccm[8];
104     u_int32_t raccm;
105     int mtu;
106     int mru;
107     int unit;
108     struct pppstat stats;
109 } ahdlc_state_t;
110
111 /* Values for flags */
112 #define ESCAPED         0x100   /* last saw escape char on input */
113 #define IFLUSH          0x200   /* flushing input due to error */
114
115 /* RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. */
116 #define RCV_FLAGS       (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
117
118 /*
119  * FCS lookup table as calculated by genfcstab.
120  */
121 static u_short fcstab[256] = {
122         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
123         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
124         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
125         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
126         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
127         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
128         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
129         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
130         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
131         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
132         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
133         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
134         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
135         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
136         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
137         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
138         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
139         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
140         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
141         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
142         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
143         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
144         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
145         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
146         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
147         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
148         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
149         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
150         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
151         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
152         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
153         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
154 };
155
156 /*
157  * STREAMS module entry points.
158  */
159 MOD_OPEN(ahdlc_open)
160 {
161     ahdlc_state_t *sp;
162
163     if (q->q_ptr == 0) {
164         sp = (ahdlc_state_t *) ALLOC_SLEEP(sizeof(ahdlc_state_t));
165         if (sp == 0)
166             OPEN_ERROR(ENOSR);
167         bzero((caddr_t) sp, sizeof(ahdlc_state_t));
168         q->q_ptr = (caddr_t) sp;
169         WR(q)->q_ptr = (caddr_t) sp;
170         sp->xaccm[0] = ~0;
171         sp->xaccm[3] = 0x60000000;
172         sp->mru = PPP_MRU;
173         qprocson(q);
174     }
175     return 0;
176 }
177
178 MOD_CLOSE(ahdlc_close)
179 {
180     ahdlc_state_t *state;
181
182     qprocsoff(q);
183     if (q->q_ptr != 0) {
184         state = (ahdlc_state_t *) q->q_ptr;
185         if (state->cur_frame != 0) {
186             freemsg(state->cur_frame);
187             state->cur_frame = 0;
188         }
189         FREE(q->q_ptr, sizeof(ahdlc_state_t));
190         q->q_ptr = NULL;
191         OTHERQ(q)->q_ptr = NULL;
192     }
193     return 0;
194 }
195
196 static int
197 ahdlc_wput(q, mp)
198     queue_t *q;
199     mblk_t *mp;
200 {
201     ahdlc_state_t *state;
202     struct iocblk *iop;
203     int error;
204     mblk_t *np;
205     struct ppp_stats *psp;
206
207     state = (ahdlc_state_t *) q->q_ptr;
208     if (state == 0) {
209         DPRINT("state == 0 in ahdlc_wput\n");
210         freemsg(mp);
211         return 0;
212     }
213
214     switch (mp->b_datap->db_type) {
215     case M_DATA:
216         /*
217          * A data packet - do character-stuffing and FCS, and
218          * send it onwards.
219          */
220         stuff_frame(q, mp);
221         freemsg(mp);
222         break;
223
224     case M_IOCTL:
225         iop = (struct iocblk *) mp->b_rptr;
226         error = EINVAL;
227         switch (iop->ioc_cmd) {
228         case PPPIO_XACCM:
229             if (iop->ioc_count < sizeof(u_int32_t)
230                 || iop->ioc_count > sizeof(ext_accm))
231                 break;
232             if (mp->b_cont == 0) {
233                 DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
234                 break;
235             }
236             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
237                   iop->ioc_count);
238             state->xaccm[2] &= ~0x40000000;     /* don't escape 0x5e */
239             state->xaccm[3] |= 0x60000000;      /* do escape 0x7d, 0x7e */
240             iop->ioc_count = 0;
241             error = 0;
242             break;
243
244         case PPPIO_RACCM:
245             if (iop->ioc_count != sizeof(u_int32_t))
246                 break;
247             if (mp->b_cont == 0) {
248                 DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
249                 break;
250             }
251             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
252                   sizeof(u_int32_t));
253             iop->ioc_count = 0;
254             error = 0;
255             break;
256
257         case PPPIO_GCLEAN:
258             np = allocb(sizeof(int), BPRI_HI);
259             if (np == 0) {
260                 error = ENOSR;
261                 break;
262             }
263             if (mp->b_cont != 0)
264                 freemsg(mp->b_cont);
265             mp->b_cont = np;
266             *(int *)np->b_wptr = state->flags & RCV_FLAGS;
267             np->b_wptr += sizeof(int);
268             iop->ioc_count = sizeof(int);
269             error = 0;
270             break;
271
272         case PPPIO_GETSTAT:
273             np = allocb(sizeof(struct ppp_stats), BPRI_HI);
274             if (np == 0) {
275                 error = ENOSR;
276                 break;
277             }
278             if (mp->b_cont != 0)
279                 freemsg(mp->b_cont);
280             mp->b_cont = np;
281             psp = (struct ppp_stats *) np->b_wptr;
282             np->b_wptr += sizeof(struct ppp_stats);
283             bzero((caddr_t)psp, sizeof(struct ppp_stats));
284             psp->p = state->stats;
285             iop->ioc_count = sizeof(struct ppp_stats);
286             error = 0;
287             break;
288
289         case PPPIO_LASTMOD:
290             /* we knew this anyway */
291             error = 0;
292             break;
293
294         default:
295             error = -1;
296             break;
297         }
298
299         if (error < 0)
300             putnext(q, mp);
301         else if (error == 0) {
302             mp->b_datap->db_type = M_IOCACK;
303             qreply(q, mp);
304         } else {
305             mp->b_datap->db_type = M_IOCNAK;
306             iop->ioc_count = 0;
307             iop->ioc_error = error;
308             qreply(q, mp);
309         }
310         break;
311
312     case M_CTL:
313         switch (*mp->b_rptr) {
314         case PPPCTL_MTU:
315             state->mtu = ((unsigned short *)mp->b_rptr)[1];
316             freemsg(mp);
317             break;
318         case PPPCTL_MRU:
319             state->mru = ((unsigned short *)mp->b_rptr)[1];
320             freemsg(mp);
321             break;
322         case PPPCTL_UNIT:
323             state->unit = mp->b_rptr[1];
324             break;
325         default:
326             putnext(q, mp);
327         }
328         break;
329
330     default:
331         putnext(q, mp);
332     }
333
334     return 0;
335 }
336
337 static int
338 ahdlc_rput(q, mp)
339     queue_t *q;
340     mblk_t *mp;
341 {
342     mblk_t *np;
343     uchar_t *cp;
344     ahdlc_state_t *state;
345
346     state = (ahdlc_state_t *) q->q_ptr;
347     if (state == 0) {
348         DPRINT("state == 0 in ahdlc_rput\n");
349         freemsg(mp);
350         return 0;
351     }
352
353     switch (mp->b_datap->db_type) {
354     case M_DATA:
355         unstuff_chars(q, mp);
356         freemsg(mp);
357         break;
358
359     case M_HANGUP:
360         if (state->cur_frame != 0) {
361             /* XXX would like to send this up for debugging */
362             freemsg(state->cur_frame);
363             state->cur_frame = 0;
364             state->cur_blk = 0;
365         }
366         state->inlen = 0;
367         state->flags = IFLUSH;
368         putnext(q, mp);
369         break;
370
371     default:
372         putnext(q, mp);
373     }
374     return 0;
375 }
376
377 /* Extract bit c from map m, to determine if c needs to be escaped. */
378 #define ESCAPE(c, m)    ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
379
380 static void
381 stuff_frame(q, mp)
382     queue_t *q;
383     mblk_t *mp;
384 {
385     ahdlc_state_t *state;
386     int ilen, olen, c, extra, i, code;
387     mblk_t *omsg, *op, *np;
388     uchar_t *sp, *sp0, *dp, *dp0, *spend;
389     ushort_t fcs;
390     u_int32_t *xaccm, lcp_xaccm[8];
391     static uchar_t lcphdr[PPP_HDRLEN] = { 0xff, 0x03, 0xc0, 0x21 };
392     uchar_t ppphdr[PPP_HDRLEN];
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, offset;
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 }