don't use options.leaf any more
[ppp.git] / osf1 / ppp_async.c
1 /*
2   ppp_async.c - Streams async functions Also does FCS
3
4   Copyright (C) 1990  Brad K. Clements, All Rights Reserved
5   fcstab and some ideas nicked from if_ppp.c from cmu.
6   See copyright notice in if_ppp.h and NOTES
7
8   $Id: ppp_async.c,v 1.1 1995/12/18 23:45:07 paulus Exp $
9 */
10
11 /*
12  * This file is used under SunOS 4.x, and OSF/1 on DEC Alpha.
13  *
14  * Beware that under OSF/1, the ioctl constants (SIOC*) end up
15  * as 64-bit (long) values, so an ioctl constant should be cast to
16  * int (32 bits) before being compared with the ioc_cmd field of
17  * an iocblk structure.
18  */
19
20 #include <sys/types.h>
21
22 #ifndef PPP_VD
23 #include "ppp.h"
24 #endif
25
26 #if NPPP > 0
27
28 #define STREAMS 1
29 #define DEBUGS  1
30 #include <sys/param.h>
31 #include <sys/stream.h>
32 #include <sys/stropts.h>
33 #include <sys/dir.h>
34 #include <sys/signal.h>
35 #include <sys/user.h>
36 #include <sys/mbuf.h>
37 #include <sys/socket.h>
38 #include <net/if.h>
39 #include <netinet/in.h>
40
41 #ifdef __osf__
42 #include <sys/proc.h>
43 #define NOTSUSER (suser(u.u_procp->p_rcred, &u.u_acflag))
44 #else
45 #define NOTSUSER (!suser())
46 #endif
47
48 #include <net/ppp_defs.h>
49 #include <net/ppp_str.h>
50
51 /* how big of a buffer block to allocate for each chunk of the input chain */
52 #define       ALLOCBSIZE      64
53
54 #ifdef  DEBUGS
55 #include <sys/syslog.h>
56 #define DLOG(s,a)       if (p->pai_flags&PAI_FLAGS_DEBUG) log(LOG_DEBUG, s, a)
57
58 int     ppp_async_max_dump_bytes = 28;
59 #define MAX_DUMP_BYTES  1504
60
61 static void ppp_dump_frame();
62
63 #else
64 #define DLOG(s) {}
65 #endif
66
67 static  int     ppp_async_open(), ppp_async_close(), ppp_async_rput(),
68         ppp_async_wput(), ppp_async_wsrv(), ppp_async_rsrv();
69
70 static  struct  module_info     minfo ={
71         0xabcd,"ppp_async",0, INFPSZ, 16384, 4096
72 };
73
74 static  struct  qinit   r_init = {
75         ppp_async_rput, ppp_async_rsrv, ppp_async_open, ppp_async_close,
76         NULL, &minfo, NULL
77 };
78 static  struct  qinit   w_init = {
79         ppp_async_wput, ppp_async_wsrv, ppp_async_open, ppp_async_close,
80         NULL, &minfo, NULL
81 };
82 struct  streamtab       ppp_asyncinfo = {
83         &r_init, &w_init, NULL, NULL,
84 };
85
86 /*
87  * FCS lookup table as calculated by genfcstab.
88  */
89 static u_short fcstab[256] = {
90         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
91         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
92         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
93         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
94         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
95         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
96         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
97         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
98         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
99         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
100         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
101         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
102         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
103         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
104         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
105         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
106         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
107         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
108         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
109         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
110         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
111         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
112         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
113         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
114         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
115         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
116         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
117         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
118         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
119         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
120         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
121         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
122 };
123
124
125 struct  ppp_async_info {
126     u_int       pai_flags;
127     int         pai_buffsize;   /* how big of an input buffer to alloc */
128     int         pai_buffcount;  /* how many chars currently in input buffer */
129     u_short     pai_fcs;        /* the current fcs */
130     mblk_t      *pai_buffer;    /* pointer to the current buffer list */
131     mblk_t      *pai_bufftail;  /* pointer to the current input block */
132     ext_accm    pai_asyncmap;   /* current outgoing asyncmap */
133     u_int32_t   pai_rasyncmap;  /* current receive asyncmap */
134 };
135
136 /* Values for pai_flags */
137 #define PAI_FLAGS_INUSE         0x1
138 #define PAI_FLAGS_FLUSH         0x2
139 #define PAI_FLAGS_ESCAPED       0x4
140 #define PAI_FLAGS_COMPPROT      0x8
141 #define PAI_FLAGS_COMPAC        0x10
142 #define PAI_FLAGS_RCV_COMPPROT  0x20
143 #define PAI_FLAGS_RCV_COMPAC    0x40
144
145 #define PAI_FLAGS_DEBUG         0x1000
146 #define PAI_FLAGS_LOG_INPKT     0x2000
147 #define PAI_FLAGS_LOG_OUTPKT    0x4000
148 #define PAI_FLAGS_ALL_DEBUG     0x7000
149
150 typedef struct ppp_async_info   PAI;
151
152 static PAI pai[NPPP*2];         /* our private cache of async ctrl structs */
153
154 /* open might fail if we don't have any more pai elements left free */
155 static int
156 ppp_async_open(q, dev, flag, sflag)
157     queue_t     *q;
158     dev_t       dev;
159     int flag;
160     int sflag;
161 {
162     register PAI *p;
163     register int x;
164     int s;
165   
166     /* only let the superuser or setuid root ppl open this module */
167     if (NOTSUSER) {
168         u.u_error = EPERM;
169         return (OPENFAIL);      
170     }
171
172     s = splstr();
173     if (!q->q_ptr) {
174         for (x=0; x < NPPP; x++)        /* search for an empty PAI */
175             if (!(pai[x].pai_flags & PAI_FLAGS_INUSE))
176                 break;
177         if (x == NPPP) {                /* all buffers in use */
178             splx(s);                    /* restore processor state */
179             u.u_error = ENOBUFS;
180             return (OPENFAIL);
181         }
182         p = &pai[x];
183         DLOG("ppp_async%d: opening\n",x);
184
185         /* initialize the unit to default values */
186         WR(q)->q_ptr = q->q_ptr =  (caddr_t) p;
187         bzero(p, sizeof(*p));
188         p->pai_flags = PAI_FLAGS_INUSE | PAI_FLAGS_RCV_COMPAC
189             | PAI_FLAGS_RCV_COMPPROT;
190         p->pai_asyncmap[0] = 0xffffffff;        /* default async map */
191         p->pai_asyncmap[3] = 0x60000000;        /* escape 7d, 7e */
192         p->pai_buffsize = PPP_MTU + PPP_HDRLEN + PPP_FCSLEN;
193     }
194     else {
195         p = (PAI *) q->q_ptr;
196         DLOG("ppp_async%d: reopen\n", p - pai);
197     }
198     
199     splx(s);
200     return(0);
201 }
202
203 static int
204 ppp_async_close(q)
205     queue_t     *q;                     /* queue info */
206 {
207     int s;
208     register PAI *p;
209   
210     s = splstr();
211     if ((p = (PAI *) q->q_ptr) != NULL) {
212         p->pai_flags = 0;               /* clear all flags */
213         if (p->pai_buffer) {
214             /* currently receiving some chars, discard the buffer */
215             freemsg(p->pai_buffer);
216             p->pai_buffer = NULL;
217         }
218         DLOG("ppp_async%d: closing\n", p - pai);
219     }
220     splx(s);
221     return(0);                  
222 }
223
224
225 /* M_IOCTL processing is performed at this level. There is some 
226    weirdness here, but I couldn't think of an easier way to handle it.
227    
228    SIOC{G,S}IF{,R,X}ASYNCMAP are handled here.
229    
230    SIOCSIFCOMPAC and SIOCSIFCOMPPROT are both handled here. 
231    
232    SIOCSIFMRU and SIOCGIFMRU (Max Receive Unit) are both handled here.
233    Rather than using the MTU to set the MRU, we have a seperate IOCTL for it.
234 */
235
236 static int
237 ppp_async_wput(q, mp)
238     queue_t  *q;
239     register mblk_t *mp;
240 {
241     register struct iocblk      *i;
242     register PAI        *p;
243     int x, flags;
244   
245     switch (mp->b_datap->db_type) {
246
247     case M_CTL:
248         switch (*(u_char *)mp->b_rptr) {
249         case IF_GET_CSTATS:
250             /* trap this and remove it */
251             freemsg(mp);
252             break;
253         default:
254             putnext(q, mp);
255         }
256         break;
257
258     case M_FLUSH :
259         if (*mp->b_rptr & FLUSHW)
260             flushq(q, FLUSHDATA);
261         putnext(q, mp);                 /* send it along too */
262         break;
263     
264     case M_DATA :
265         putq(q, mp);                    /* queue it for my service routine */
266         break;
267     
268     case M_IOCTL :
269         i = (struct iocblk *) mp->b_rptr;
270         p = (PAI *) q->q_ptr;
271         switch (i->ioc_cmd) {
272       
273         case SIOCSIFCOMPAC :    /* enable or disable AC compression */
274             if (i->ioc_count != sizeof(u_char)) {
275                 i->ioc_error = EINVAL;
276                 goto iocnak;
277             }
278             x = *(u_char *) mp->b_cont->b_rptr;
279             DLOG("ppp_async: SIFCOMPAC %d\n", x);
280             flags = (x & 2)? PAI_FLAGS_RCV_COMPAC: PAI_FLAGS_COMPAC;
281             if (x & 1) 
282                 p->pai_flags |= flags;
283             else
284                 p->pai_flags &= ~flags;
285             i->ioc_count = 0;
286             goto iocack;
287
288         case SIOCSIFCOMPPROT:   /* enable or disable PROT  compression */
289             if (i->ioc_count != sizeof(u_char)) {
290                 i->ioc_error = EINVAL;
291                 goto iocnak;
292             }
293             x = *(u_char *) mp->b_cont->b_rptr;
294             DLOG("ppp_async: SIFCOMPPROT %d\n", x);
295             flags = (x & 2)? PAI_FLAGS_RCV_COMPPROT: PAI_FLAGS_COMPPROT;
296             if (x & 1) 
297                 p->pai_flags |= flags;
298             else
299                 p->pai_flags &= ~flags;
300             i->ioc_count = 0;
301             goto iocack;
302       
303       
304         case SIOCSIFMRU :
305             if (i->ioc_count != sizeof(int)) {
306                 i->ioc_error = EINVAL;
307                 goto iocnak;
308             }
309             x = *(int *) mp->b_cont->b_rptr;
310             if (x < PPP_MTU)
311                 x = PPP_MTU;
312             x += PPP_HDRLEN + PPP_FCSLEN;
313             if (x > 4096) {     /* couldn't allocb something this big */
314                 i->ioc_error = EINVAL;
315                 goto iocnak;
316             }
317             p->pai_buffsize = x;
318             i->ioc_count  = 0;
319             goto iocack;
320
321         case SIOCGIFMRU :
322             if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) {
323                 *(int *) mp->b_cont->b_wptr = 
324                     p->pai_buffsize - (PPP_HDRLEN + PPP_FCSLEN);
325                 mp->b_cont->b_wptr += i->ioc_count  = sizeof(int);
326                 goto iocack;
327             }
328             i->ioc_error = ENOSR;
329             goto iocnak;
330       
331         case SIOCGIFASYNCMAP :
332             if ((mp->b_cont = allocb(sizeof(u_int32_t), BPRI_MED)) != NULL) {
333                 *(u_int32_t *) mp->b_cont->b_wptr = p->pai_asyncmap[0];
334                 mp->b_cont->b_wptr += i->ioc_count = sizeof(u_int32_t);
335                 goto iocack;
336             }
337             i->ioc_error = ENOSR;
338             goto iocnak;
339
340         case SIOCSIFASYNCMAP :
341             if (i->ioc_count != sizeof(u_int32_t)) {
342                 i->ioc_error = EINVAL;
343                 goto iocnak;    /* ugh, goto */
344             }
345             p->pai_asyncmap[0] = *(u_int32_t *) mp->b_cont->b_rptr;
346             DLOG("ppp_async: SIFASYNCMAP %lx\n", p->pai_asyncmap[0]);
347             i->ioc_count = 0;
348             goto iocack;
349
350         case SIOCGIFRASYNCMAP :
351             if ((mp->b_cont = allocb(sizeof(u_int32_t), BPRI_MED)) != NULL) {
352                 *(u_int32_t *) mp->b_cont->b_wptr = p->pai_rasyncmap;
353                 mp->b_cont->b_wptr += i->ioc_count = sizeof(u_int32_t);
354                 goto iocack;
355             }
356             i->ioc_error = ENOSR;
357             goto iocnak;
358
359         case SIOCSIFRASYNCMAP :
360             if (i->ioc_count != sizeof(u_int32_t)) {
361                 i->ioc_error = EINVAL;
362                 goto iocnak;    /* ugh, goto */
363             }
364             p->pai_rasyncmap = *(u_int32_t *) mp->b_cont->b_rptr;
365             DLOG("ppp_async: SIFRASYNCMAP %lx\n", p->pai_rasyncmap);
366             i->ioc_count = 0;
367             goto iocack;
368
369         case SIOCGIFXASYNCMAP :
370             if ((mp->b_cont = allocb(sizeof(ext_accm), BPRI_MED)) != NULL) {
371                 bcopy(p->pai_asyncmap, mp->b_cont->b_wptr, sizeof(ext_accm));
372                 mp->b_cont->b_wptr += i->ioc_count = sizeof(ext_accm);
373                 goto iocack;
374             }
375             i->ioc_error = ENOSR;
376             goto iocnak;
377
378         case SIOCSIFXASYNCMAP :
379             if (i->ioc_count != sizeof(ext_accm)) {
380                 i->ioc_error = EINVAL;
381                 goto iocnak;    /* ugh, goto */
382             }
383             bcopy(mp->b_cont->b_rptr, p->pai_asyncmap, sizeof(ext_accm));
384             p->pai_asyncmap[1] = 0;             /* can't escape 20-3f */
385             p->pai_asyncmap[2] &= ~0x40000000;  /* can't escape 5e */
386             p->pai_asyncmap[3] |= 0x60000000;   /* must escape 7d, 7e */
387             i->ioc_count = 0;
388             goto iocack;
389
390         case SIOCGIFDEBUG :
391             if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) {
392                 *(int *)mp->b_cont->b_wptr =
393                     (unsigned)(p->pai_flags & PAI_FLAGS_ALL_DEBUG)
394                         / PAI_FLAGS_DEBUG |
395                     (p->pai_flags & PAI_FLAGS_HIBITS);
396                 mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
397                 goto iocack;
398             }
399             i->ioc_error = ENOSR;
400             goto iocnak;
401
402         case SIOCSIFDEBUG :
403             if(i->ioc_count != sizeof(int)) {
404                 i->ioc_error = EINVAL;
405                 goto iocnak;    /* ugh, goto */
406             }
407             flags = *(int *)mp->b_cont->b_rptr;
408             DLOG("ppp_async: SIFIFDEBUG %x\n", flags);
409             p->pai_flags &= ~PAI_FLAGS_ALL_DEBUG | PAI_FLAGS_HIBITS;
410             p->pai_flags |= ((unsigned) flags * PAI_FLAGS_DEBUG)
411                 & PAI_FLAGS_ALL_DEBUG;
412             i->ioc_count = 0;
413             goto iocack;
414
415         iocack:;
416             mp->b_datap->db_type = M_IOCACK;
417             qreply(q,mp);
418             break;
419         iocnak:;
420             i->ioc_count = 0;
421             mp->b_datap->db_type = M_IOCNAK;
422             qreply(q, mp);
423             break;
424         default:                                /* unknown IOCTL call */
425             putnext(q,mp);              /* pass it along */
426         }
427         break;
428
429     default:
430         putnext(q, mp); /* don't know what to do with this, so send it along*/
431     }
432 }
433
434 static int
435 ppp_async_wsrv(q)
436     queue_t     *q;
437 {
438     register u_char     *cp, *wp;
439     register PAI        *p;
440     register u_short    fcs;
441     register mblk_t     *mp, *m0;
442     mblk_t      *cop, *outgoing;
443     int proto, len, olen, c;
444
445     p = (PAI *) q->q_ptr;
446
447     while ((mp = getq(q)) != NULL) {
448         /*
449          * we can only get M_DATA types into our Queue,
450          * due to our Put function
451          */
452         if (!canput(q->q_next)) {
453             putbq(q, mp);
454             return;
455         }
456
457         /* at least a header required */
458         len = msgdsize(mp);
459         if (len < PPP_HDRLEN
460             || (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
461                 && !pullupmsg(mp, PPP_HDRLEN))) {       
462             freemsg(mp);                /* discard the message */
463             DLOG("ppp_async: short message (%d)\n", len);
464             /* indicate output err */
465             putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR);
466             continue;
467         }
468
469         /* Do address/control and protocol compression */
470         proto = (mp->b_rptr[2] << 8) + mp->b_rptr[3];
471         if (p->pai_flags & PAI_FLAGS_COMPAC && proto != PPP_LCP
472             && mp->b_rptr[0] == PPP_ALLSTATIONS && mp->b_rptr[1] == PPP_UI) {
473             mp->b_rptr += 2;
474             if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff)
475                 ++mp->b_rptr;
476         } else if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff) {
477             mp->b_rptr[2] = mp->b_rptr[1];
478             mp->b_rptr[1] = mp->b_rptr[0];
479             ++mp->b_rptr;
480         }
481
482         m0 = mp;                /* remember first message block */
483         fcs = PPP_INITFCS;
484
485         /*
486          * Estimate the required buffer length as 1.25 * message length
487          * to allow for escaped characters.  If this isn't enough, we
488          * allocate another buffer later.
489          */
490         olen = len + (len >> 2) + 5;
491         if (olen < 32)
492             olen = 32;
493         else if (olen > 2048)
494             olen = 2048;
495         outgoing = cop = allocb(olen, BPRI_MED);
496         if (outgoing == NULL) {
497             DLOG("allocb(%d) failed!\n", olen);
498             /* should do something tricky here */
499             goto nobuffs;
500         }
501         wp = cop->b_wptr;
502
503         /* Put the initial flag in (we'll take it out later if we don't
504            need it). */
505         *wp++ = PPP_FLAG;
506         --olen;
507
508 #define SPECIAL(p, c)   (p->pai_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
509
510         /*
511          * Copy the message to the output block, escaping characters
512          * as needed.
513          */
514         while (mp) {
515             for (cp = mp->b_rptr; cp < mp->b_wptr; ) {
516                 c = *cp++;
517                 if (olen < 2) {
518                     /* grab another message block and put it on the end */
519                     cop->b_wptr = wp;
520                     olen = 256;
521                     cop = allocb(olen, BPRI_MED);
522                     if (cop == NULL)
523                         goto nobuffs;
524                     linkb(outgoing, cop);
525                     wp = cop->b_wptr;
526                 }
527                 if (SPECIAL(p, c)) {
528                     *wp++ = PPP_ESCAPE;
529                     *wp++ = c ^ PPP_TRANS;
530                     olen -= 2;
531                 } else {
532                     *wp++ = c;
533                     --olen;
534                 }
535                 fcs = PPP_FCS(fcs, c);
536             }
537             mp = mp->b_cont; /* look at the next block */
538         }                                       /* end while(mp) */
539
540         /*
541          * Add the FCS and the trailing flag.
542          */
543         if (olen < 5) {
544             /* grab another message block for FCS and trailing flag */
545             cop->b_wptr = wp;
546             cop = allocb(5, BPRI_MED);
547             if (cop == NULL)
548                 goto nobuffs;
549             linkb(outgoing, cop);
550             wp = cop->b_wptr;
551         }
552         fcs ^= 0xffff;                          /* XOR the resulting FCS */
553         c = fcs & 0xff;
554         if (SPECIAL(p, c)) {
555             *wp++ = PPP_ESCAPE;
556             *wp++ = c ^ PPP_TRANS;
557         } else
558             *wp++ = c;
559         c = fcs >> 8;
560         if (SPECIAL(p, c)) {
561             *wp++ = PPP_ESCAPE;
562             *wp++ = c ^ PPP_TRANS;
563         } else
564             *wp++  = c;
565         *wp++ = PPP_FLAG;       /* add trailing PPP_FLAG */
566
567         cop->b_wptr = wp;
568         freemsg(m0);
569
570         /*
571          * now we check to see if the lower queue has entries, if so,
572          * we assume that we don't need a leading PPP_FLAG because
573          * these packets will be sent back to back.
574          */
575         if (qsize(q->q_next) > 0) {
576             /* entries in next queue, remove the leading PPP_FLAG */
577             ++outgoing->b_rptr;
578         }
579
580 #if DEBUGS
581         if (p->pai_flags & PAI_FLAGS_LOG_OUTPKT)
582             ppp_dump_frame(p, outgoing, " sent output");
583 #endif
584         putnext(q, outgoing);
585         continue;
586
587     nobuffs:    /* well, we ran out of memory somewhere */
588         if (outgoing)
589             freemsg(outgoing);          /* throw away what we have already */
590         putbq(q, m0);                   /* put back the original message */
591         putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR);
592         qenable(q);                     /* reschedule ourselves for later */
593         return;
594     } /* end while(getq()) */
595 }       /* end function */                                      
596
597 static int
598 ppp_async_rput(q, mp)
599     queue_t *q;
600     register mblk_t *mp;
601 {
602     switch (mp->b_datap->db_type) {
603     
604     case M_FLUSH:
605         if(*mp->b_rptr & FLUSHR)
606             flushq(q, FLUSHDATA);
607         putnext(q, mp);         /* send it along too */
608         break;
609     
610     case M_DATA:
611         putq(q, mp);            /* queue it for my service routine */
612         break;
613     
614     default:
615         putnext(q,mp);  /* don't know what to do with this, so send it along */
616     }
617 }
618
619 static u_int32_t paritytab[8] = {
620     0x96696996, 0x69969669, 0x69969669, 0x96696996,
621     0x69969669, 0x96696996, 0x96696996, 0x69969669,
622 };
623
624 static int
625 ppp_async_rsrv(q)
626     queue_t     *q;
627 {
628     register mblk_t *mp, *bp;
629     register PAI        *p;
630     register u_char     *cp,c;
631     mblk_t      *m0;
632     register u_char *wptr;
633     int bcount;
634   
635     p = (PAI *) q->q_ptr;
636
637 #define INPUT_ERROR(q)  putctl1(q, M_CTL, IF_INPUT_ERROR)
638 #define STUFF_CHAR(p,c) (*wptr++ = (c), (p)->pai_buffcount++)
639 #define FLUSHEM(q, p)   (INPUT_ERROR(q), (p)->pai_flags |= PAI_FLAGS_FLUSH)
640   
641     while ((mp = getq(q)) != NULL) {
642         /* we can only get M_DATA types into our Queue,
643            due to our Put function */
644         if (!canput(q->q_next)) {
645             putbq(q, mp);
646             return;
647         }
648         m0 = mp;        /* remember first message block */
649         for (; mp != NULL; mp = mp->b_cont) {   /* for each message block */
650             cp = mp->b_rptr;
651             while (cp < mp->b_wptr) {
652                 c = *cp++;
653
654                 /* Accumulate info to help with detecting
655                    non 8-bit clean links. */
656                 if (c & 0x80)
657                     p->pai_flags |= PAI_FLAGS_B7_1;
658                 else
659                     p->pai_flags |= PAI_FLAGS_B7_0;
660                 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
661                     p->pai_flags |= PAI_FLAGS_PAR_ODD;
662                 else
663                     p->pai_flags |= PAI_FLAGS_PAR_EVEN;
664
665                 /* Throw out chars in the receive asyncmap. */
666                 if (c < 0x20 && (p->pai_rasyncmap & (1 << c)))
667                     continue;
668
669                 /* A flag marks the end of a frame. */
670                 if (c == PPP_FLAG) {
671                     bp = p->pai_buffer;
672                     bcount = p->pai_buffcount;
673                     p->pai_buffer = NULL;
674                     p->pai_buffcount = 0;
675
676                     /* if the escape indicator is set, then we have
677                        seen the packet abort sequence "}~". */
678                     if (p->pai_flags & (PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH)) {
679                         if ((p->pai_flags & PAI_FLAGS_FLUSH) == 0)
680                             DLOG("ppp_async: packet abort\n", 0);
681                         p->pai_flags &= ~(PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH);
682                         if (bp)
683                             freemsg(bp);
684                         continue;
685                     }
686
687                     if (bcount > PPP_FCSLEN) {  /* discard FCS */
688                         adjmsg(bp, -PPP_FCSLEN);
689                         bcount -= PPP_FCSLEN;
690                     }
691
692                     if (bcount < PPP_HDRLEN) {
693                         if (bcount) {
694                             INPUT_ERROR(q);
695                             DLOG("ppp_async: short input packet (%d)\n",
696                                  bcount);
697                         }
698                         if (bp)
699                             freemsg(bp);
700                         continue;
701                     }
702
703                     if (bp) {
704                         if (p->pai_fcs == PPP_GOODFCS) {
705 #if DEBUGS
706                             if (p->pai_flags & PAI_FLAGS_LOG_INPKT)
707                                 ppp_dump_frame(p, bp, " got input");
708 #endif /*DEBUGS*/
709                             putnext(q, bp);
710                         }
711                         else {
712                             INPUT_ERROR(q);
713                             freemsg(bp);
714                             DLOG("ppp_async: FCS Error\n", 0);
715                         }
716                     }
717                     continue;
718                 }
719
720                 /* here c != PPP_FLAG */
721                 if (p->pai_flags & PAI_FLAGS_FLUSH) {
722                     while (cp < mp->b_wptr && *cp != PPP_FLAG)
723                         ++cp;
724                     continue;
725                 }
726
727                 if (p->pai_flags & PAI_FLAGS_ESCAPED) {
728                     p->pai_flags &= ~PAI_FLAGS_ESCAPED; /* clear esc flag */
729                     c ^= PPP_TRANS;
730                 } else if (c == PPP_ESCAPE) {
731                     if (cp >= mp->b_wptr || (c = *cp) == PPP_FLAG
732                         || c < 0x20 && (p->pai_rasyncmap & (1 << c))) {
733                         p->pai_flags |= PAI_FLAGS_ESCAPED;
734                         continue;
735                     }
736                     c ^= PPP_TRANS;
737                     ++cp;
738                 }
739
740                 /* here we check to see if we have a buffer.
741                    If we don't, we assume that this is the first char
742                    for the buffer, and we allocb one */
743         
744                 if (!p->pai_buffer) {
745                     /* we allocate buffer chains in blocks of ALLOCBSIZE */
746           
747                     if (!(p->pai_buffer = allocb(ALLOCBSIZE, BPRI_MED))) {
748                         FLUSHEM(q, p);
749                         continue;
750                         /* if we don't get a buffer, is there some way
751                            to recover and requeue later? rather than flushing
752                            the current packet... ? */
753                     }
754                     p->pai_bufftail = p->pai_buffer;
755                 }
756                 wptr = p->pai_bufftail->b_wptr;
757
758                 if (!p->pai_buffcount) {
759                     p->pai_fcs = PPP_INITFCS;
760                     if (c != PPP_ALLSTATIONS) {
761                         if (p->pai_flags & PAI_FLAGS_RCV_COMPAC) {
762                             STUFF_CHAR(p, PPP_ALLSTATIONS);
763                             STUFF_CHAR(p, PPP_UI);
764                         }
765                         else {
766                             DLOG("ppp_async: missed ALLSTATIONS (0xff), got 0x%x\n", c);
767                             FLUSHEM(q, p);
768                             continue;
769                         }
770                     }
771                 } /* end if !p->pai_buffcount */
772
773                 if (p->pai_buffcount == 1 && c != PPP_UI) {
774                     DLOG("ppp_async: missed UI (0x3), got 0x%x\n", c);
775                     FLUSHEM(q,p);
776                     continue;
777                 }
778
779                 if (p->pai_buffcount == 2 && (c & 1) == 1) {
780                     if (p->pai_flags & PAI_FLAGS_RCV_COMPPROT)
781                         STUFF_CHAR(p, 0);
782                     else {
783                         DLOG("ppp_async: bad protocol high byte %x\n", c);
784                         FLUSHEM(q, p);
785                         continue;
786                     }
787                 }
788
789                 if (p->pai_buffcount == 3 && (c & 1) == 0) {
790                     DLOG("ppp_async: bad protocol low byte %x\n", c);
791                     FLUSHEM(q, p);
792                     continue;
793                 }
794
795                 if (p->pai_buffcount >= p->pai_buffsize) {      /* overrun */
796                     DLOG("ppp_async: too many chars in input buffer %d\n",
797                          p->pai_buffcount);
798                     FLUSHEM(q, p);
799                     continue;
800                 }
801
802                 /* determine if we have enough space in the buffer */
803                 if (wptr >= p->pai_bufftail->b_datap->db_lim) {
804                     p->pai_bufftail->b_wptr = wptr;
805                     if (!(p->pai_bufftail = allocb(ALLOCBSIZE, BPRI_MED))) {
806                         DLOG("ppp_async: couldn't get buffer for tail\n", 0);
807                         FLUSHEM(q, p);  /* discard all of it */
808                         continue;
809                     }
810                     linkb(p->pai_buffer, p->pai_bufftail);
811                     wptr = p->pai_bufftail->b_wptr;
812                 }
813
814                 STUFF_CHAR(p, c);
815                 p->pai_fcs = PPP_FCS(p->pai_fcs, c);
816
817                 if (p->pai_buffcount >= PPP_HDRLEN) {
818                     while (cp < mp->b_wptr
819                            && wptr < p->pai_bufftail->b_datap->db_lim
820                            && (c = *cp) != PPP_FLAG && c != PPP_ESCAPE) {
821                         if (c >= 0x20 || (p->pai_rasyncmap & (1 << c)) == 0) {
822                             STUFF_CHAR(p, c);
823                             p->pai_fcs = PPP_FCS(p->pai_fcs, c);
824                         }
825                         ++cp;
826                     }
827                 }
828
829                 p->pai_bufftail->b_wptr = wptr;
830
831             } /* end while cp < wptr */
832         }       /* end for each block */
833         /* discard this message now */
834         freemsg(m0);
835     }   /* end while  getq */
836   
837 }
838
839 #if DEBUGS
840 /*
841  * here is where we will dump out a frame in hex using the log() 
842  * function if ppp_async_input_debug is non-zero. As this function is
843  * a pig, we only print up to the number of bytes specified by the value of
844  * the ppp_async_max_dump_bytes variable so as to not cause too many
845  * timeouts.   <gmc@quotron.com> 
846  */
847
848 static void
849 ppp_dump_frame(p, mptr, msg)
850     register PAI *p;
851     register mblk_t *mptr;
852     char *msg;
853 {
854     register u_char *rptr;
855     register u_int i, mlen, frame_length;
856     char buf[2*MAX_DUMP_BYTES+4];       /* tmp buffer */
857     char *bp = buf;
858     static char digits[] = "0123456789abcdef";
859
860     frame_length = i = msgdsize(mptr);
861     log(LOG_INFO, "ppp_async%d:%s frame of %d bytes\n", p - pai,
862         msg, frame_length); 
863     rptr = mptr->b_rptr; /* get pointer to beginning  */
864     mlen = mptr->b_wptr - rptr; /* get length of this dblock */
865
866     /* only dump up to MAX_DUMP_BYTES */
867     if (i > ppp_async_max_dump_bytes)
868         i = ppp_async_max_dump_bytes;   
869
870     while (i--) {                       /* convert to ascii hex */
871         while (mlen == 0) {             /* get next dblock */
872             mptr = mptr->b_cont;
873             if (mptr) { /* are we done? */
874                 rptr = mptr->b_rptr;    /* nope, get next dblock */
875                 mlen = mptr->b_wptr - rptr;
876             }
877             else {                      /* no more dblocks */
878                 if (i != 0)
879                     log(LOG_ERR, "ppp_async: ran out of data! (this shouldn't happen\n");
880                 break;
881             }
882         }
883         --mlen;
884         *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
885         *bp++ = digits[*rptr++ & 0xf];
886     }
887
888     /* add a '>' to show that frame was truncated*/
889     if (ppp_async_max_dump_bytes < frame_length)
890         *bp++ = '>';
891     *bp = 0;
892     log(LOG_INFO,"ppp_async: %s\n", buf); 
893 }
894 #endif /* DEBUGS */
895
896 #endif /* NPPP > 0 */