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