More debugging.
[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.7 1998/03/24 23:52:35 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         --ppp_ahdlc_count;
194     }
195     return 0;
196 }
197
198 static int
199 ahdlc_wput(q, mp)
200     queue_t *q;
201     mblk_t *mp;
202 {
203     ahdlc_state_t *state;
204     struct iocblk *iop;
205     int error;
206     mblk_t *np;
207     struct ppp_stats *psp;
208
209     state = (ahdlc_state_t *) q->q_ptr;
210     switch (mp->b_datap->db_type) {
211     case M_DATA:
212         /*
213          * A data packet - do character-stuffing and FCS, and
214          * send it onwards.
215          */
216         stuff_frame(q, mp);
217         freemsg(mp);
218         break;
219
220     case M_IOCTL:
221         iop = (struct iocblk *) mp->b_rptr;
222         error = EINVAL;
223         switch (iop->ioc_cmd) {
224         case PPPIO_XACCM:
225             if (iop->ioc_count < sizeof(u_int32_t)
226                 || iop->ioc_count > sizeof(ext_accm))
227                 break;
228             if (mp->b_cont == 0) {
229                 DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
230                 break;
231             }
232             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
233                   iop->ioc_count);
234             state->xaccm[2] &= ~0x40000000;     /* don't escape 0x5e */
235             state->xaccm[3] |= 0x60000000;      /* do escape 0x7d, 0x7e */
236             iop->ioc_count = 0;
237             error = 0;
238             break;
239
240         case PPPIO_RACCM:
241             if (iop->ioc_count != sizeof(u_int32_t))
242                 break;
243             if (mp->b_cont == 0) {
244                 DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
245                 break;
246             }
247             bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
248                   sizeof(u_int32_t));
249             iop->ioc_count = 0;
250             error = 0;
251             break;
252
253         case PPPIO_GCLEAN:
254             np = allocb(sizeof(int), BPRI_HI);
255             if (np == 0) {
256                 error = ENOSR;
257                 break;
258             }
259             if (mp->b_cont != 0)
260                 freemsg(mp->b_cont);
261             mp->b_cont = np;
262             *(int *)np->b_wptr = state->flags & RCV_FLAGS;
263             np->b_wptr += sizeof(int);
264             iop->ioc_count = sizeof(int);
265             error = 0;
266             break;
267
268         case PPPIO_GETSTAT:
269             np = allocb(sizeof(struct ppp_stats), BPRI_HI);
270             if (np == 0) {
271                 error = ENOSR;
272                 break;
273             }
274             if (mp->b_cont != 0)
275                 freemsg(mp->b_cont);
276             mp->b_cont = np;
277             psp = (struct ppp_stats *) np->b_wptr;
278             np->b_wptr += sizeof(struct ppp_stats);
279             bzero((caddr_t)psp, sizeof(struct ppp_stats));
280             psp->p = state->stats;
281             iop->ioc_count = sizeof(struct ppp_stats);
282             error = 0;
283             break;
284
285         case PPPIO_LASTMOD:
286             /* we knew this anyway */
287             error = 0;
288             break;
289
290         default:
291             error = -1;
292             break;
293         }
294
295         if (error < 0)
296             putnext(q, mp);
297         else if (error == 0) {
298             mp->b_datap->db_type = M_IOCACK;
299             qreply(q, mp);
300         } else {
301             mp->b_datap->db_type = M_IOCNAK;
302             iop->ioc_count = 0;
303             iop->ioc_error = error;
304             qreply(q, mp);
305         }
306         break;
307
308     case M_CTL:
309         switch (*mp->b_rptr) {
310         case PPPCTL_MTU:
311             state->mtu = ((unsigned short *)mp->b_rptr)[1];
312             freemsg(mp);
313             break;
314         case PPPCTL_MRU:
315             state->mru = ((unsigned short *)mp->b_rptr)[1];
316             freemsg(mp);
317             break;
318         case PPPCTL_UNIT:
319             state->unit = mp->b_rptr[1];
320             break;
321         default:
322             putnext(q, mp);
323         }
324         break;
325
326     default:
327         putnext(q, mp);
328     }
329     return 0;
330 }
331
332 static int
333 ahdlc_rput(q, mp)
334     queue_t *q;
335     mblk_t *mp;
336 {
337     mblk_t *np;
338     uchar_t *cp;
339     ahdlc_state_t *state;
340
341     switch (mp->b_datap->db_type) {
342     case M_DATA:
343         unstuff_chars(q, mp);
344         freemsg(mp);
345         break;
346
347     case M_HANGUP:
348         state = (ahdlc_state_t *) q->q_ptr;
349         if (state->cur_frame != 0) {
350             /* XXX would like to send this up for debugging */
351             freemsg(state->cur_frame);
352             state->cur_frame = 0;
353             state->cur_blk = 0;
354         }
355         state->inlen = 0;
356         state->flags = IFLUSH;
357         putnext(q, mp);
358         break;
359
360     default:
361         putnext(q, mp);
362     }
363     return 0;
364 }
365
366 /* Extract bit c from map m, to determine if c needs to be escaped. */
367 #define ESCAPE(c, m)    ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
368
369 static void
370 stuff_frame(q, mp)
371     queue_t *q;
372     mblk_t *mp;
373 {
374     ahdlc_state_t *state;
375     int ilen, olen, c, extra, i, code;
376     mblk_t *omsg, *op, *np;
377     uchar_t *sp, *sp0, *dp, *dp0, *spend;
378     ushort_t fcs;
379     u_int32_t *xaccm, lcp_xaccm[8];
380     static uchar_t lcphdr[PPP_HDRLEN] = { 0xff, 0x03, 0xc0, 0x21 };
381     uchar_t ppphdr[PPP_HDRLEN];
382
383     state = (ahdlc_state_t *) q->q_ptr;
384     ilen = msgdsize(mp);
385
386     /*
387      * We estimate the length of the output packet as
388      * 1.25 * input length + 16 (for initial flag, FCS, final flag, slop).
389      */
390     olen = ilen + (ilen >> 2) + 16;
391     if (olen > OFRAME_BSIZE)
392         olen = OFRAME_BSIZE;
393     omsg = op = allocb(olen, BPRI_MED);
394     if (omsg == 0)
395         goto bomb;
396
397     /*
398      * Put in an initial flag for now.  We'll remove it later
399      * if we decide we don't need it.
400      */
401     dp = op->b_wptr;
402     *dp++ = PPP_FLAG;
403     --olen;
404
405     /*
406      * For LCP packets with code values between 1 and 7 (Conf-Req
407      * to Code-Rej), we must escape all control characters.
408      */
409     xaccm = state->xaccm;
410     if (MSG_BYTE(mp, 0) == PPP_ALLSTATIONS
411         && MSG_BYTE(mp, 1) == PPP_UI
412         && MSG_BYTE(mp, 2) == (PPP_LCP >> 8)
413         && MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)
414         && LCP_USE_DFLT(mp)) {
415         bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, sizeof(lcp_xaccm));
416         lcp_xaccm[0] = ~0;
417         xaccm = lcp_xaccm;
418     }
419
420     sp = mp->b_rptr;
421     fcs = PPP_INITFCS;
422     for (;;) {
423         spend = mp->b_wptr;
424         extra = sp + olen - spend;
425         if (extra < 0) {
426             spend = sp + olen;
427             extra = 0;
428         }
429         /*
430          * We can safely process the input up to `spend'
431          * without overrunning the output, provided we don't
432          * hit more than `extra' characters which need to be escaped.
433          */
434         sp0 = sp;
435         dp0 = dp;
436         while (sp < spend) {
437             c = *sp;
438             if (ESCAPE(c, xaccm)) {
439                 if (extra > 0)
440                     --extra;
441                 else if (sp < spend - 1)
442                     --spend;
443                 else
444                     break;
445                 fcs = PPP_FCS(fcs, c);
446                 *dp++ = PPP_ESCAPE;
447                 c ^= PPP_TRANS;
448             } else
449                 fcs = PPP_FCS(fcs, c);
450             *dp++ = c;
451             ++sp;
452         }
453         ilen -= sp - sp0;
454         olen -= dp - dp0;
455
456         /*
457          * At this point, we have emptied an input block
458          * and/or filled an output block.
459          */
460         if (sp >= mp->b_wptr) {
461             /*
462              * We've emptied an input block.  Advance to the next.
463              */
464             mp = mp->b_cont;
465             if (mp == 0)
466                 break;          /* all done */
467             sp = mp->b_rptr;
468         }
469         if (olen < 2) {
470             /*
471              * The output block is full.  Allocate a new one.
472              */
473             op->b_wptr = dp;
474             olen = 2 * ilen + 5;
475             if (olen > OFRAME_BSIZE)
476                 olen = OFRAME_BSIZE;
477             np = allocb(olen, BPRI_MED);
478             if (np == 0)
479                 goto bomb;
480             op->b_cont = np;
481             op = np;
482             dp = op->b_wptr;
483         }
484     }
485
486     /*
487      * Append the FCS and closing flag.
488      * This could require up to 5 characters.
489      */
490     if (olen < 5) {
491         /* Sigh.  Need another block. */
492         op->b_wptr = dp;
493         np = allocb(5, BPRI_MED);
494         if (np == 0)
495             goto bomb;
496         op->b_cont = np;
497         op = np;
498         dp = op->b_wptr;
499     }
500     c = ~fcs & 0xff;
501     if (ESCAPE(c, xaccm)) {
502         *dp++ = PPP_ESCAPE;
503         c ^= PPP_TRANS;
504     }
505     *dp++ = c;
506     c = (~fcs >> 8) & 0xff;
507     if (ESCAPE(c, xaccm)) {
508         *dp++ = PPP_ESCAPE;
509         c ^= PPP_TRANS;
510     }
511     *dp++ = c;
512     *dp++ = PPP_FLAG;
513     op->b_wptr = dp;
514
515     /*
516      * Remove the initial flag, if possible.
517      */
518     if (qsize(q->q_next) > 0)
519         ++omsg->b_rptr;
520
521     /*
522      * Update statistics.
523      */
524     state->stats.ppp_obytes += msgdsize(omsg);
525     state->stats.ppp_opackets++;
526
527     /*
528      * Send it on.
529      */
530     putnext(q, omsg);
531     return;
532
533  bomb:
534     if (omsg != 0)
535         freemsg(omsg);
536     state->stats.ppp_oerrors++;
537     putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
538 }
539
540 #define UPDATE_FLAGS(c) {                               \
541     if ((c) & 0x80)                                     \
542         state->flags |= RCV_B7_1;                       \
543     else                                                \
544         state->flags |= RCV_B7_0;                       \
545     if (0x6996 & (1 << ((((c) >> 4) ^ (c)) & 0xf)))     \
546         state->flags |= RCV_ODDP;                       \
547     else                                                \
548         state->flags |= RCV_EVNP;                       \
549 }
550
551 /*
552  * Process received characters.
553  */
554 static void
555 unstuff_chars(q, mp)
556     queue_t *q;
557     mblk_t *mp;
558 {
559     ahdlc_state_t *state;
560     mblk_t *om;
561     uchar_t *cp, *cpend, *dp, *dp0;
562     int c, len, extra, offset;
563     ushort_t fcs;
564
565     state = (ahdlc_state_t *) q->q_ptr;
566     state->stats.ppp_ibytes += msgdsize(mp);
567     cp = mp->b_rptr;
568     for (;;) {
569         /*
570          * Advance to next input block if necessary.
571          */
572         if (cp >= mp->b_wptr) {
573             mp = mp->b_cont;
574             if (mp == 0)
575                 break;
576             cp = mp->b_rptr;
577             continue;
578         }
579
580         if ((state->flags & (IFLUSH|ESCAPED)) == 0
581             && state->inlen > 0 && (om = state->cur_blk) != 0) {
582             /*
583              * Process bulk chars as quickly as possible.
584              */
585             dp = om->b_wptr;
586             len = om->b_datap->db_lim - dp; /* max # output bytes */
587             extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
588             if (extra < 0) {
589                 len += extra;               /* we'll run out of input first */
590                 extra = 0;
591             }
592             cpend = cp + len;
593             dp0 = dp;
594             fcs = state->infcs;
595             while (cp < cpend) {
596                 c = *cp;
597                 if (c == PPP_FLAG)
598                     break;
599                 ++cp;
600                 UPDATE_FLAGS(c);
601                 if (c == PPP_ESCAPE) {
602                     if (extra > 0) {
603                         --extra;
604                         ++cpend;
605                     }
606                     if (cp >= cpend || (c = *cp) == PPP_FLAG) {
607                         state->flags |= ESCAPED;
608                         break;
609                     }
610                     ++cp;
611                     UPDATE_FLAGS(c);
612                     c ^= PPP_TRANS;
613                 }
614                 *dp++ = c;
615                 fcs = PPP_FCS(fcs, c);
616             }
617             state->inlen += dp - dp0;
618             state->infcs = fcs;
619             om->b_wptr = dp;
620             if (cp >= mp->b_wptr)
621                 continue;       /* advance to the next mblk */
622         }
623
624         c = *cp++;
625         UPDATE_FLAGS(c);
626         if (c == PPP_FLAG) {
627             /*
628              * End of a frame.
629              * If the ESCAPE flag is set, the frame ended with
630              * the frame abort sequence "}~".
631              */
632             om = state->cur_frame;
633             len = state->inlen;
634             state->cur_frame = 0;
635             state->inlen = 0;
636             if (len == 0 && (state->flags & IFLUSH) == 0)
637                 continue;
638             state->stats.ppp_ipackets++;
639             if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0
640                 && len > PPP_FCSLEN) {
641                 if (state->infcs == PPP_GOODFCS) {
642                     adjmsg(om, -PPP_FCSLEN);    /* chop off fcs */
643                     putnext(q, om);             /* bombs away! */
644                     continue;
645                 }
646                 DPRINT2("ppp%d: bad fcs (len=%d)\n", state->unit, len);
647             }
648             if (om != 0)
649                 freemsg(om);
650             state->flags &= ~(IFLUSH|ESCAPED);
651             state->stats.ppp_ierrors++;
652             putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
653             continue;
654         }
655
656         if (state->flags & IFLUSH)
657             continue;
658         if (state->flags & ESCAPED) {
659             c ^= PPP_TRANS;
660             state->flags &= ~ESCAPED;
661         } else if (c == PPP_ESCAPE) {
662             state->flags |= ESCAPED;
663             continue;
664         }
665         if (state->inlen == 0) {
666             /*
667              * First byte of the frame: allocate the first message block.
668              */
669             om = allocb(IFRAME_BSIZE, BPRI_MED);
670             if (om == 0) {
671                 state->flags |= IFLUSH;
672                 continue;
673             }
674             state->cur_frame = om;
675             state->cur_blk = om;
676             state->infcs = PPP_INITFCS;
677         } else {
678             om = state->cur_blk;
679             if (om->b_wptr >= om->b_datap->db_lim) {
680                 /*
681                  * Current message block is full.  Allocate another one,
682                  * unless we have run out of MRU.
683                  */
684                 if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
685                     state->flags |= IFLUSH;
686                     DPRINT2("ppp%d: frame too long (%d)\n",
687                             state->unit, state->inlen);
688                     continue;
689                 }
690                 om = allocb(IFRAME_BSIZE, BPRI_MED);
691                 if (om == 0) {
692                     state->flags |= IFLUSH;
693                     continue;
694                 }
695                 state->cur_blk->b_cont = om;
696                 state->cur_blk = om;
697             }
698         }
699
700         if (state->inlen == 0) {
701             /*
702              * We don't do address/control & protocol decompression here,
703              * but we try to put the first byte at an offset such that
704              * the info field starts on a word boundary.  The code here
705              * will do this except for packets with protocol compression
706              * but not address/control compression.
707              */
708             if (c != PPP_ALLSTATIONS) {
709                 om->b_wptr += 2;
710                 if (c & 1)
711                     ++om->b_wptr;
712                 om->b_rptr = om->b_wptr;
713             }
714         }
715
716         *om->b_wptr++ = c;
717         ++state->inlen;
718         state->infcs = PPP_FCS(state->infcs, c);
719     }
720 }
721
722 static int
723 msg_byte(mp, i)
724     mblk_t *mp;
725     unsigned int i;
726 {
727     while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
728         mp = mp->b_cont;
729     if (mp == 0)
730         return -1;
731     return mp->b_rptr[i];
732 }