use crtscts = -2 to indicate xon/xoff
[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.4 1995/08/10 06:54:20 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 #define UPDATE_FLAGS(c) {                               \
570     if ((c) & 0x80)                                     \
571         state->flags |= RCV_B7_1;                       \
572     else                                                \
573         state->flags |= RCV_B7_0;                       \
574     if (paritytab[(c) >> 5] & (1 << ((c) & 0x1F)))      \
575         state->flags |= RCV_ODDP;                       \
576     else                                                \
577         state->flags |= RCV_EVNP;                       \
578 }
579
580 /*
581  * Process received characters.
582  */
583 static void
584 unstuff_chars(q, mp)
585     queue_t *q;
586     mblk_t *mp;
587 {
588     ahdlc_state_t *state;
589     mblk_t *om;
590     uchar_t *cp, *cpend, *dp, *dp0;
591     int c, len, extra, offset;
592     ushort_t fcs;
593
594     state = (ahdlc_state_t *) q->q_ptr;
595     state->stats.ppp_ibytes += msgdsize(mp);
596     cp = mp->b_rptr;
597     for (;;) {
598         /*
599          * Advance to next input block if necessary.
600          */
601         if (cp >= mp->b_wptr) {
602             mp = mp->b_cont;
603             if (mp == 0)
604                 break;
605             cp = mp->b_rptr;
606             continue;
607         }
608
609         if ((state->flags & (IFLUSH|ESCAPED)) == 0
610             && state->inlen >= PPP_HDRLEN
611             && (om = state->cur_blk) != 0) {
612             /*
613              * Process bulk chars as quickly as possible.
614              */
615             dp = om->b_wptr;
616             len = om->b_datap->db_lim - dp; /* max # output bytes */
617             extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
618             if (extra < 0) {
619                 len += extra;               /* we'll run out of input first */
620                 extra = 0;
621             }
622             cpend = cp + len;
623             dp0 = dp;
624             fcs = state->infcs;
625             while (cp < cpend) {
626                 c = *cp;
627                 if (c == PPP_FLAG)
628                     break;
629                 ++cp;
630                 UPDATE_FLAGS(c);
631                 if (c == PPP_ESCAPE) {
632                     if (extra > 0) {
633                         --extra;
634                         ++cpend;
635                     }
636                     if (cp >= cpend || (c = *cp) == PPP_FLAG) {
637                         state->flags |= ESCAPED;
638                         break;
639                     }
640                     ++cp;
641                     UPDATE_FLAGS(c);
642                     c ^= PPP_TRANS;
643                 }
644                 *dp++ = c;
645                 fcs = PPP_FCS(fcs, c);
646             }
647             state->inlen += dp - dp0;
648             state->infcs = fcs;
649             om->b_wptr = dp;
650             if (cp >= mp->b_wptr)
651                 continue;       /* advance to the next mblk */
652         }
653
654         c = *cp++;
655         UPDATE_FLAGS(c);
656         if (c == PPP_FLAG) {
657             /*
658              * End of a frame.
659              * If the ESCAPE flag is set, the frame ended with
660              * the frame abort sequence "}~".
661              */
662             om = state->cur_frame;
663             len = state->inlen;
664             state->cur_frame = 0;
665             state->inlen = 0;
666             if (len == 0 && (state->flags & IFLUSH) == 0)
667                 continue;
668             state->stats.ppp_ipackets++;
669             if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0
670                 && len > PPP_FCSLEN) {
671                 if (state->infcs == PPP_GOODFCS) {
672                     adjmsg(om, -PPP_FCSLEN);    /* chop off fcs */
673                     putnext(q, om);             /* bombs away! */
674                     continue;
675                 }
676 #if DEBUG
677                 cmn_err(CE_CONT, "ppp_ahdl: bad fcs %x\n", state->infcs);
678 #endif
679             }
680             if (om != 0)
681                 freemsg(om);
682             state->stats.ppp_ierrors++;
683             putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
684             continue;
685         }
686
687         if (state->flags & IFLUSH)
688             continue;
689         if (state->flags & ESCAPED) {
690             c ^= PPP_TRANS;
691             state->flags &= ~ESCAPED;
692         } else if (c == PPP_ESCAPE) {
693             state->flags |= ESCAPED;
694             continue;
695         }
696         if (state->inlen == 0) {
697             /*
698              * First byte of the frame: allocate the first message block.
699              */
700             om = allocb(IFRAME_BSIZE, BPRI_MED);
701             if (om == 0) {
702                 state->flags |= IFLUSH;
703                 continue;
704             }
705             state->cur_frame = om;
706             state->cur_blk = om;
707             state->infcs = PPP_INITFCS;
708         } else {
709             om = state->cur_blk;
710             if (om->b_wptr >= om->b_datap->db_lim) {
711                 /*
712                  * Current message block is full.  Allocate another one,
713                  * unless we have run out of MRU.
714                  */
715                 if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
716 #if DEBUG
717                     cmn_err(CE_CONT, "ppp_ahdl: frame too long (%d)\n",
718                             state->inlen);
719 #endif
720                     state->flags |= IFLUSH;
721                     continue;
722                 }
723                 om = allocb(IFRAME_BSIZE, BPRI_MED);
724                 if (om == 0) {
725                     state->flags |= IFLUSH;
726                     continue;
727                 }
728                 state->cur_blk->b_cont = om;
729                 state->cur_blk = om;
730             }
731         }
732         *om->b_wptr++ = c;
733         ++state->inlen;
734         state->infcs = PPP_FCS(state->infcs, c);
735
736         if (state->inlen == PPP_HDRLEN) {
737             /*
738              * We don't do address/control & protocol decompression here,
739              * but we do leave space for the decompressed fields and
740              * arrange for the info field to start on a word boundary.
741              */
742             dp = om->b_rptr;
743             if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS
744                 && PPP_CONTROL(dp) == PPP_UI)
745                 dp += 2;
746             if ((*dp & 1) == 0)
747                 ++dp;
748             /* dp is now pointing at the last byte of the ppp protocol field */
749             offset = 3 - ((unsigned)dp & 3);
750             if (offset > 0) {
751                 dp = om->b_wptr;
752                 do {
753                     --dp;
754                     dp[offset] = dp[0];
755                 } while (dp > om->b_rptr);
756                 om->b_rptr += offset;
757                 om->b_wptr += offset;
758             }
759         }
760     }
761 }
762
763 static int
764 msg_copy(buf, mp, n)
765     uchar_t *buf;
766     mblk_t *mp;
767     int n;
768 {
769     int i;
770     uchar_t *cp;
771
772     cp = mp->b_rptr;
773     for (i = 0; i < n; ++i) {
774         if (cp >= mp->b_wptr) {
775             do {
776                 if ((mp = mp->b_cont) == 0)
777                     return i;
778             } while (mp->b_rptr >= mp->b_wptr);
779             cp = mp->b_rptr;
780         }
781         buf[i] = *cp++;
782     }
783     return n;
784 }