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