]> git.ozlabs.org Git - ppp.git/blob - svr4/ppp_ahdlc.c
dc35dda51c9688feb97a53d8eccc0c66259d1f69
[ppp.git] / svr4 / 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 HAVE 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.3 1995/05/29 06:45:49 paulus Exp $
28  */
29
30 /*
31  * This file is used under Solaris 2.
32  */
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/stream.h>
37 #include <sys/conf.h>
38 #include <sys/kmem.h>
39 #include <sys/errno.h>
40 #include <sys/cmn_err.h>
41 #include <sys/ddi.h>
42 #ifdef sun
43 #include <sys/modctl.h>
44 #include <sys/sunddi.h>
45 #endif
46 #include <net/ppp_defs.h>
47 #include <net/pppio.h>
48
49 #define IFRAME_BSIZE    512     /* Block size to allocate for input */
50 #define OFRAME_BSIZE    4096    /* Don't allocb more than this for output */
51
52 static int ahdlc_open __P((queue_t *, dev_t *, int, int, cred_t *));
53 static int ahdlc_close __P((queue_t *, int, cred_t *));
54 static int ahdlc_wput __P((queue_t *, mblk_t *));
55 static int ahdlc_rput __P((queue_t *, mblk_t *));
56 static void stuff_frame __P((queue_t *, mblk_t *));
57 static void unstuff_chars __P((queue_t *, mblk_t *));
58 static int msg_copy __P((uchar_t *, mblk_t *, int));
59
60 static struct module_info minfo = {
61     0x7d23, "ppp_ahdl", 0, INFPSZ, 4096, 128
62 };
63
64 static struct qinit rinit = {
65     ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
66 };
67
68 static struct qinit winit = {
69     ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
70 };
71
72 static struct streamtab ahdlc_info = {
73     &rinit, &winit, NULL, NULL
74 };
75
76 #ifdef sun
77 static struct fmodsw fsw = {
78     "ppp_ahdl",
79     &ahdlc_info,
80     D_NEW | D_MP | D_MTQPAIR
81 };
82
83 extern struct mod_ops mod_strmodops;
84
85 static struct modlstrmod modlstrmod = {
86     &mod_strmodops,
87     "PPP async HDLC module",
88     &fsw
89 };
90
91 static struct modlinkage modlinkage = {
92     MODREV_1,
93     (void *) &modlstrmod,
94     NULL
95 };
96 #endif /* sun */
97
98 typedef struct ahdlc_state {
99     int flags;
100     mblk_t *cur_frame;
101     mblk_t *cur_blk;
102     int inlen;
103     ushort infcs;
104     u_int32_t xaccm[8];
105     u_int32_t raccm;
106     int mtu;
107     int mru;
108     int unit;
109     struct pppstat stats;
110 } ahdlc_state_t;
111
112 /* Values for flags */
113 #define ESCAPED         0x100   /* last saw escape char on input */
114 #define IFLUSH          0x200   /* flushing input due to error */
115
116 /* RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. */
117 #define RCV_FLAGS       (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
118
119 #ifndef sun
120 # define qprocson(q)
121 # define qprocsoff(q)
122 #endif
123
124 /*
125  * FCS lookup table as calculated by genfcstab.
126  */
127 static u_short fcstab[256] = {
128         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
129         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
130         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
131         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
132         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
133         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
134         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
135         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
136         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
137         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
138         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
139         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
140         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
141         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
142         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
143         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
144         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
145         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
146         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
147         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
148         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
149         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
150         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
151         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
152         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
153         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
154         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
155         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
156         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
157         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
158         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
159         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
160 };
161
162 #ifdef sun
163 /*
164  * Entry points for modloading.
165  */
166 int
167 _init(void)
168 {
169     return mod_install(&modlinkage);
170 }
171
172 int
173 _fini(void)
174 {
175     return mod_remove(&modlinkage);
176 }
177
178 int
179 _info(mip)
180     struct modinfo *mip;
181 {
182     return mod_info(&modlinkage, mip);
183 }
184 #endif
185
186 /*
187  * STREAMS module entry points.
188  */
189 static int
190 ahdlc_open(q, devp, flag, sflag, credp)
191     queue_t *q;
192     dev_t *devp;
193     int flag, sflag;
194     cred_t *credp;
195 {
196     ahdlc_state_t *sp;
197
198     if (q->q_ptr == 0) {
199         sp = (ahdlc_state_t *) kmem_zalloc(sizeof(ahdlc_state_t), KM_SLEEP);
200         if (sp == 0)
201             return ENOSR;
202         q->q_ptr = sp;
203         WR(q)->q_ptr = sp;
204         sp->xaccm[0] = ~0;
205         sp->xaccm[3] = 0x60000000;
206         sp->mru = 1500;
207         qprocson(q);
208     }
209     return 0;
210 }
211
212 static int
213 ahdlc_close(q, flag, credp)
214     queue_t *q;
215     int flag;
216     cred_t *credp;
217 {
218     ahdlc_state_t *state;
219
220     qprocsoff(q);
221     if (q->q_ptr != 0) {
222         state = (ahdlc_state_t *) q->q_ptr;
223         if (state->cur_frame != 0) {
224             freemsg(state->cur_frame);
225             state->cur_frame = 0;
226         }
227         kmem_free(q->q_ptr, sizeof(ahdlc_state_t));
228     }
229     return 0;
230 }
231
232 static int
233 ahdlc_wput(q, mp)
234     queue_t *q;
235     mblk_t *mp;
236 {
237     ahdlc_state_t *state;
238     struct iocblk *iop;
239     int error;
240     mblk_t *np;
241     struct ppp_stats *psp;
242
243     state = (ahdlc_state_t *) q->q_ptr;
244     switch (mp->b_datap->db_type) {
245     case M_DATA:
246         /*
247          * A data packet - do character-stuffing and FCS, and
248          * send it onwards.
249          */
250         stuff_frame(q, mp);
251         freemsg(mp);
252         break;
253
254     case M_IOCTL:
255         iop = (struct iocblk *) mp->b_rptr;
256         error = EINVAL;
257         switch (iop->ioc_cmd) {
258         case PPPIO_XACCM:
259             if (iop->ioc_count < sizeof(u_int32_t)
260                 || iop->ioc_count > sizeof(ext_accm))
261                 break;
262             bcopy(mp->b_cont->b_rptr, (caddr_t)state->xaccm, iop->ioc_count);
263             state->xaccm[2] &= 0x40000000;      /* don't escape 0x5e */
264             state->xaccm[3] |= 0x60000000;      /* do escape 0x7d, 0x7e */
265             iop->ioc_count = 0;
266             error = 0;
267             break;
268
269         case PPPIO_RACCM:
270             if (iop->ioc_count != sizeof(u_int32_t))
271                 break;
272             bcopy(mp->b_cont->b_rptr, (caddr_t)&state->raccm,
273                   sizeof(u_int32_t));
274             iop->ioc_count = 0;
275             error = 0;
276             break;
277
278         case PPPIO_GCLEAN:
279             np = allocb(sizeof(int), BPRI_HI);
280             if (np == 0) {
281                 error = ENOSR;
282                 break;
283             }
284             if (mp->b_cont != 0)
285                 freemsg(mp->b_cont);
286             mp->b_cont = np;
287             *(int *)np->b_wptr = state->flags & RCV_FLAGS;
288             np->b_wptr += sizeof(int);
289             iop->ioc_count = sizeof(int);
290             error = 0;
291             break;
292
293         case PPPIO_GETSTAT:
294             np = allocb(sizeof(struct ppp_stats), BPRI_HI);
295             if (np == 0) {
296                 error = ENOSR;
297                 break;
298             }
299             if (mp->b_cont != 0)
300                 freemsg(mp->b_cont);
301             mp->b_cont = np;
302             psp = (struct ppp_stats *) np->b_wptr;
303             np->b_wptr += sizeof(struct ppp_stats);
304             bzero((caddr_t)psp, sizeof(struct ppp_stats));
305             psp->p = state->stats;
306             iop->ioc_count = sizeof(struct ppp_stats);
307             error = 0;
308             break;
309
310         case PPPIO_LASTMOD:
311             /* we knew this anyway */
312             error = 0;
313             break;
314
315         default:
316             error = -1;
317             break;
318         }
319
320         if (error < 0)
321             putnext(q, mp);
322         else if (error == 0) {
323             mp->b_datap->db_type = M_IOCACK;
324             qreply(q, mp);
325         } else {
326             mp->b_datap->db_type = M_IOCNAK;
327             iop->ioc_count = 0;
328             iop->ioc_error = error;
329             qreply(q, mp);
330         }
331         break;
332
333     case M_CTL:
334         switch (*mp->b_rptr) {
335         case PPPCTL_MTU:
336             state->mtu = ((unsigned short *)mp->b_rptr)[1];
337             freemsg(mp);
338             break;
339         case PPPCTL_MRU:
340             state->mru = ((unsigned short *)mp->b_rptr)[1];
341             freemsg(mp);
342             break;
343         case PPPCTL_UNIT:
344             state->unit = mp->b_rptr[1];
345             break;
346         default:
347             putnext(q, mp);
348         }
349         break;
350
351     default:
352         putnext(q, mp);
353     }
354     return 0;
355 }
356
357 static int
358 ahdlc_rput(q, mp)
359     queue_t *q;
360     mblk_t *mp;
361 {
362     mblk_t *np;
363     uchar_t *cp;
364     ahdlc_state_t *state;
365
366     switch (mp->b_datap->db_type) {
367     case M_DATA:
368         unstuff_chars(q, mp);
369         freemsg(mp);
370         break;
371
372     case M_HANGUP:
373         state = (ahdlc_state_t *) q->q_ptr;
374         if (state->cur_frame != 0) {
375             /* XXX would like to send this up for debugging */
376             freemsg(state->cur_frame);
377             state->cur_frame = 0;
378             state->cur_blk = 0;
379         }
380         state->inlen = 0;
381         state->flags = IFLUSH;
382         putnext(q, mp);
383         break;
384
385     default:
386         putnext(q, mp);
387     }
388     return 0;
389 }
390
391 /* Extract bit c from map m, to determine if c needs to be escaped. */
392 #define ESCAPE(c, m)    ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
393
394 static void
395 stuff_frame(q, mp)
396     queue_t *q;
397     mblk_t *mp;
398 {
399     ahdlc_state_t *state;
400     int ilen, olen, c, extra, i;
401     mblk_t *omsg, *op, *np;
402     uchar_t *sp, *sp0, *dp, *dp0, *spend;
403     ushort_t fcs;
404     u_int32_t *xaccm, lcp_xaccm[8];
405     static uchar_t lcphdr[PPP_HDRLEN] = { 0xff, 0x03, 0xc0, 0x21 };
406     uchar_t ppphdr[PPP_HDRLEN];
407
408     state = (ahdlc_state_t *) q->q_ptr;
409     ilen = msgdsize(mp);
410
411     /*
412      * We estimate the length of the output packet as
413      * 1.25 * input length + 16 (for initial flag, FCS, final flag, slop).
414      */
415     olen = ilen + (ilen >> 2) + 16;
416     if (olen > OFRAME_BSIZE)
417         olen = OFRAME_BSIZE;
418     omsg = op = allocb(olen, BPRI_MED);
419     if (omsg == 0)
420         goto bomb;
421
422     /*
423      * Put in an initial flag for now.  We'll remove it later
424      * if we decide we don't need it.
425      */
426     dp = op->b_wptr;
427     *dp++ = PPP_FLAG;
428     --olen;
429
430     /*
431      * For LCP packets, we must escape all control characters.
432      * Inspect the first PPP_HDRLEN bytes of the message to
433      * see whether it is an LCP packet.
434      * LCP packets must not be A/C or protocol compressed.
435      */
436     xaccm = state->xaccm;
437     if (msg_copy(ppphdr, mp, PPP_HDRLEN) == PPP_HDRLEN
438         && bcmp((caddr_t) ppphdr, (caddr_t) lcphdr, PPP_HDRLEN) == 0) {
439         bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, sizeof(lcp_xaccm));
440         lcp_xaccm[0] = ~0;
441         xaccm = lcp_xaccm;
442     }
443
444     sp = mp->b_rptr;
445     fcs = PPP_INITFCS;
446     for (;;) {
447         spend = mp->b_wptr;
448         extra = sp + olen - spend;
449         if (extra < 0) {
450             spend = sp + olen;
451             extra = 0;
452         }
453         /*
454          * We can safely process the input up to `spend'
455          * without overrunning the output, provided we don't
456          * hit more than `extra' characters which need to be escaped.
457          */
458         sp0 = sp;
459         dp0 = dp;
460         while (sp < spend) {
461             c = *sp;
462             if (ESCAPE(c, xaccm)) {
463                 if (extra > 0)
464                     --extra;
465                 else if (sp < spend - 1)
466                     --spend;
467                 else
468                     break;
469                 fcs = PPP_FCS(fcs, c);
470                 *dp++ = PPP_ESCAPE;
471                 c ^= PPP_TRANS;
472             } else
473                 fcs = PPP_FCS(fcs, c);
474             *dp++ = c;
475             ++sp;
476         }
477         ilen -= sp - sp0;
478         olen -= dp - dp0;
479
480         /*
481          * At this point, we have emptied an input block
482          * and/or filled an output block.
483          */
484         if (sp >= mp->b_wptr) {
485             /*
486              * We've emptied an input block.  Advance to the next.
487              */
488             mp = mp->b_cont;
489             if (mp == 0)
490                 break;          /* all done */
491             sp = mp->b_rptr;
492         }
493         if (olen < 2) {
494             /*
495              * The output block is full.  Allocate a new one.
496              */
497             op->b_wptr = dp;
498             olen = 2 * ilen + 5;
499             if (olen > OFRAME_BSIZE)
500                 olen = OFRAME_BSIZE;
501             np = allocb(olen, BPRI_MED);
502             if (np == 0)
503                 goto bomb;
504             op->b_cont = np;
505             op = np;
506             dp = op->b_wptr;
507         }
508     }
509
510     /*
511      * Append the FCS and closing flag.
512      * This could require up to 5 characters.
513      */
514     if (olen < 5) {
515         /* Sigh.  Need another block. */
516         op->b_wptr = dp;
517         np = allocb(5, BPRI_MED);
518         if (np == 0)
519             goto bomb;
520         op->b_cont = np;
521         op = np;
522         dp = op->b_wptr;
523     }
524     c = ~fcs & 0xff;
525     if (ESCAPE(c, xaccm)) {
526         *dp++ = PPP_ESCAPE;
527         c ^= PPP_TRANS;
528     }
529     *dp++ = c;
530     c = (~fcs >> 8) & 0xff;
531     if (ESCAPE(c, xaccm)) {
532         *dp++ = PPP_ESCAPE;
533         c ^= PPP_TRANS;
534     }
535     *dp++ = c;
536     *dp++ = PPP_FLAG;
537     op->b_wptr = dp;
538
539     /*
540      * Remove the initial flag, if possible.
541      */
542     if (qsize(q->q_next) > 0)
543         ++omsg->b_rptr;
544
545     /*
546      * Update statistics.
547      */
548     state->stats.ppp_obytes += msgdsize(omsg);
549     state->stats.ppp_opackets++;
550
551     /*
552      * Send it on.
553      */
554     putnext(q, omsg);
555     return;
556
557  bomb:
558     if (omsg != 0)
559         freemsg(omsg);
560     state->stats.ppp_oerrors++;
561     putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
562 }
563
564 static unsigned paritytab[8] = {
565     0x96696996, 0x69969669, 0x69969669, 0x96696996,
566     0x69969669, 0x96696996, 0x96696996, 0x69969669
567 };
568
569 /*
570  * Process received characters.
571  */
572 static void
573 unstuff_chars(q, mp)
574     queue_t *q;
575     mblk_t *mp;
576 {
577     ahdlc_state_t *state;
578     mblk_t *om;
579     uchar_t *cp, *cpend, *dp, *dp0;
580     int c, len, extra, offset;
581     ushort_t fcs;
582
583     state = (ahdlc_state_t *) q->q_ptr;
584     state->stats.ppp_ibytes += msgdsize(mp);
585     cp = mp->b_rptr;
586     for (;;) {
587         /*
588          * Advance to next input block if necessary.
589          */
590         if (cp >= mp->b_wptr) {
591             mp = mp->b_cont;
592             if (mp == 0)
593                 break;
594             cp = mp->b_rptr;
595             continue;
596         }
597
598         if ((state->flags & (IFLUSH|ESCAPED)) == 0
599             && state->inlen >= PPP_HDRLEN
600             && (om = state->cur_blk) != 0) {
601             /*
602              * Process bulk chars as quickly as possible.
603              */
604             dp = om->b_wptr;
605             len = om->b_datap->db_lim - dp; /* max # output bytes */
606             extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
607             if (extra < 0) {
608                 len += extra;               /* we'll run out of input first */
609                 extra = 0;
610             }
611             cpend = cp + len;
612             dp0 = dp;
613             fcs = state->infcs;
614             while (cp < cpend) {
615                 c = *cp;
616                 if (c == PPP_FLAG)
617                     break;
618                 ++cp;
619                 if (c & 0x80)
620                     state->flags |= RCV_B7_1;
621                 else
622                     state->flags |= RCV_B7_0;
623                 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
624                     state->flags |= RCV_ODDP;
625                 else
626                     state->flags |= RCV_EVNP;
627                 if (c == PPP_ESCAPE) {
628                     if (extra > 0) {
629                         --extra;
630                         ++cpend;
631                     } else if (cp >= cpend) {
632                         state->flags |= ESCAPED;
633                         break;
634                     }
635                     c = *cp;
636                     if (c == PPP_FLAG)
637                         break;
638                     ++cp;
639                     c ^= PPP_TRANS;
640                 }
641                 *dp++ = c;
642                 fcs = PPP_FCS(fcs, c);
643             }
644             state->inlen += dp - dp0;
645             state->infcs = fcs;
646             om->b_wptr = dp;
647             if (cp >= cpend)
648                 continue;       /* go back and check cp again */
649         }
650
651         c = *cp++;
652         if (c & 0x80)
653             state->flags |= RCV_B7_1;
654         else
655             state->flags |= RCV_B7_0;
656         if (paritytab[c >> 5] & (1 << (c & 0x1F)))
657             state->flags |= RCV_ODDP;
658         else
659             state->flags |= RCV_EVNP;
660         if (c == PPP_FLAG) {
661             /*
662              * End of a frame.
663              * If the ESCAPE flag is set, the frame ended with
664              * the frame abort sequence "}~".
665              */
666             om = state->cur_frame;
667             len = state->inlen;
668             state->cur_frame = 0;
669             state->inlen = 0;
670             if (len == 0 && (state->flags & IFLUSH) == 0)
671                 continue;
672             state->stats.ppp_ipackets++;
673             if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0
674                 && len > PPP_FCSLEN) {
675                 if (state->infcs == PPP_GOODFCS) {
676                     adjmsg(om, -PPP_FCSLEN);    /* chop off fcs */
677                     putnext(q, om);             /* bombs away! */
678                     continue;
679                 }
680 #if DEBUG
681                 cmn_err(CE_CONT, "ppp_ahdl: bad fcs %x\n", state->infcs);
682 #endif
683             }
684             if (om != 0)
685                 freemsg(om);
686             state->stats.ppp_ierrors++;
687             putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
688             continue;
689         }
690
691         if (state->flags & IFLUSH)
692             continue;
693         if (state->flags & ESCAPED) {
694             c ^= PPP_TRANS;
695             state->flags &= ~ESCAPED;
696         } else if (c == PPP_ESCAPE) {
697             state->flags |= ESCAPED;
698             continue;
699         }
700         if (state->inlen == 0) {
701             /*
702              * First byte of the frame: allocate the first message block.
703              */
704             om = allocb(IFRAME_BSIZE, BPRI_MED);
705             if (om == 0) {
706                 state->flags |= IFLUSH;
707                 continue;
708             }
709             state->cur_frame = om;
710             state->cur_blk = om;
711             state->infcs = PPP_INITFCS;
712         } else {
713             om = state->cur_blk;
714             if (om->b_wptr >= om->b_datap->db_lim) {
715                 /*
716                  * Current message block is full.  Allocate another one,
717                  * unless we have run out of MRU.
718                  */
719                 if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
720 #if DEBUG
721                     cmn_err(CE_CONT, "ppp_ahdl: frame too long (%d)\n",
722                             state->inlen);
723 #endif
724                     state->flags |= IFLUSH;
725                     continue;
726                 }
727                 om = allocb(IFRAME_BSIZE, BPRI_MED);
728                 if (om == 0) {
729                     state->flags |= IFLUSH;
730                     continue;
731                 }
732                 state->cur_blk->b_cont = om;
733                 state->cur_blk = om;
734             }
735         }
736         *om->b_wptr++ = c;
737         ++state->inlen;
738         state->infcs = PPP_FCS(state->infcs, c);
739
740         if (state->inlen == PPP_HDRLEN) {
741             /*
742              * We don't do address/control & protocol decompression here,
743              * but we do leave space for the decompressed fields and
744              * arrange for the info field to start on a word boundary.
745              */
746             dp = om->b_rptr;
747             if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS
748                 && PPP_CONTROL(dp) == PPP_UI)
749                 dp += 2;
750             if ((*dp & 1) == 0)
751                 ++dp;
752             /* dp is now pointing at the last byte of the ppp protocol field */
753             offset = 3 - ((unsigned)dp & 3);
754             if (offset > 0) {
755                 dp = om->b_wptr;
756                 do {
757                     --dp;
758                     dp[offset] = dp[0];
759                 } while (dp > om->b_rptr);
760                 om->b_rptr += offset;
761                 om->b_wptr += offset;
762             }
763         }
764     }
765 }
766
767 static int
768 msg_copy(buf, mp, n)
769     uchar_t *buf;
770     mblk_t *mp;
771     int n;
772 {
773     int i;
774     uchar_t *cp;
775
776     cp = mp->b_rptr;
777     for (i = 0; i < n; ++i) {
778         if (cp >= mp->b_wptr) {
779             do {
780                 if ((mp = mp->b_cont) == 0)
781                     return i;
782             } while (mp->b_rptr >= mp->b_wptr);
783             cp = mp->b_rptr;
784         }
785         buf[i] = *cp++;
786     }
787     return n;
788 }