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