fix up prototypes; let sysdep stuff make device non-blocking
[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.3 1995/04/26 04:15:48 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_CTL:
249         switch (*(u_char *)mp->b_rptr) {
250         case IF_GET_CSTATS:
251             /* trap this and remove it */
252             freemsg(mp);
253             break;
254         default:
255             putnext(q, mp);
256         }
257         break;
258    
259     case M_FLUSH :
260         if (*mp->b_rptr & FLUSHW)
261             flushq(q, FLUSHDATA);
262         putnext(q, mp);                 /* send it along too */
263         break;
264     
265     case M_DATA :
266         putq(q, mp);                    /* queue it for my service routine */
267         break;
268     
269     case M_IOCTL :
270         i = (struct iocblk *) mp->b_rptr;
271         p = (PAI *) q->q_ptr;
272         switch ((unsigned int)i->ioc_cmd) {
273       
274         case SIOCSIFCOMPAC :    /* enable or disable AC compression */
275             if (i->ioc_count != TRANSPARENT) {
276                 i->ioc_error = EINVAL;
277                 goto iocnak;
278             }
279             x = *(u_int *) mp->b_cont->b_rptr;
280             DLOG("ppp_async: SIFCOMPAC %d\n", x);
281             flags = (x & 2)? PAI_FLAGS_RCV_COMPAC: PAI_FLAGS_COMPAC;
282             if (x & 1) 
283                 p->pai_flags |= flags;
284             else
285                 p->pai_flags &= ~flags;
286             i->ioc_count = 0;
287             goto iocack;
288
289         case SIOCSIFCOMPPROT:   /* enable or disable PROT  compression */
290             if (i->ioc_count != TRANSPARENT) {
291                 i->ioc_error = EINVAL;
292                 goto iocnak;
293             }
294             x = *(u_int *) mp->b_cont->b_rptr;
295             DLOG("ppp_async: SIFCOMPPROT %d\n", x);
296             flags = (x & 2)? PAI_FLAGS_RCV_COMPPROT: PAI_FLAGS_COMPPROT;
297             if (x & 1) 
298                 p->pai_flags |= flags;
299             else
300                 p->pai_flags &= ~flags;
301             i->ioc_count = 0;
302             goto iocack;
303       
304       
305         case SIOCSIFMRU :
306             if ((i->ioc_count != TRANSPARENT) &&
307                 (i->ioc_count != sizeof(int))) {
308                 i->ioc_error = EINVAL;
309                 goto iocnak;
310             }
311             x = *(int *) mp->b_cont->b_rptr;
312             if (x < PPP_MTU)
313                 x = PPP_MTU;
314             x += PPP_HDRLEN + PPP_FCSLEN;
315             if (x > 4096) {     /* couldn't allocb something this big */
316                 i->ioc_error = EINVAL;
317                 goto iocnak;
318             }
319             p->pai_buffsize = x;
320             i->ioc_count  = 0;
321             goto iocack;
322
323         case SIOCGIFMRU :
324             if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) {
325                 *(int *) mp->b_cont->b_wptr = 
326                     p->pai_buffsize - (PPP_HDRLEN + PPP_FCSLEN);
327                 mp->b_cont->b_wptr += i->ioc_count  = sizeof(int);
328                 goto iocack;
329             }
330             i->ioc_error = ENOSR;
331             goto iocnak;
332       
333         case SIOCGIFASYNCMAP :
334             if ((mp->b_cont = allocb(sizeof(u_int32_t), BPRI_MED)) != NULL) {
335                 *(u_int32_t *) mp->b_cont->b_wptr = p->pai_asyncmap[0];
336                 mp->b_cont->b_wptr += i->ioc_count = sizeof(u_int32_t);
337                 goto iocack;
338             }
339             i->ioc_error = ENOSR;
340             goto iocnak;
341
342         case SIOCSIFASYNCMAP :
343             if ((i->ioc_count != TRANSPARENT) &&
344                 (i->ioc_count != sizeof(u_int32_t))) {
345                 i->ioc_error = EINVAL;
346                 goto iocnak;    /* ugh, goto */
347             }
348             p->pai_asyncmap[0] = *(u_int32_t *) mp->b_cont->b_rptr;
349             DLOG("ppp_async: SIFASYNCMAP %lx\n", p->pai_asyncmap[0]);
350             i->ioc_count = 0;
351             goto iocack;
352
353         case SIOCGIFRASYNCMAP :
354             if ((mp->b_cont = allocb(sizeof(u_int32_t), BPRI_MED)) != NULL) {
355                 *(u_int32_t *) mp->b_cont->b_wptr = p->pai_rasyncmap;
356                 mp->b_cont->b_wptr += i->ioc_count = sizeof(u_int32_t);
357                 goto iocack;
358             }
359             i->ioc_error = ENOSR;
360             goto iocnak;
361
362         case SIOCSIFRASYNCMAP :
363             if ((i->ioc_count != TRANSPARENT) &&
364                 (i->ioc_count != sizeof(u_int32_t))) {
365                 i->ioc_error = EINVAL;
366                 goto iocnak;    /* ugh, goto */
367             }
368             p->pai_rasyncmap = *(u_int32_t *) mp->b_cont->b_rptr;
369             DLOG("ppp_async: SIFRASYNCMAP %lx\n", p->pai_rasyncmap);
370             i->ioc_count = 0;
371             goto iocack;
372
373         case SIOCGIFXASYNCMAP :
374             if ((mp->b_cont = allocb(sizeof(ext_accm), BPRI_MED)) != NULL) {
375                 bcopy(p->pai_asyncmap, mp->b_cont->b_wptr, sizeof(ext_accm));
376                 mp->b_cont->b_wptr += i->ioc_count = sizeof(ext_accm);
377                 goto iocack;
378             }
379             i->ioc_error = ENOSR;
380             goto iocnak;
381
382         case SIOCSIFXASYNCMAP :
383             if ((i->ioc_count != TRANSPARENT) &&
384                 (i->ioc_count != sizeof(ext_accm))) {
385                 i->ioc_error = EINVAL;
386                 goto iocnak;    /* ugh, goto */
387             }
388             bcopy(*mp->b_cont->b_rptr, p->pai_asyncmap, sizeof(ext_accm));
389             p->pai_asyncmap[1] = 0;             /* can't escape 20-3f */
390             p->pai_asyncmap[2] &= ~0x40000000;  /* can't escape 5e */
391             p->pai_asyncmap[3] |= 0x60000000;   /* must escape 7d, 7e */
392             i->ioc_count = 0;
393             goto iocack;
394
395         case SIOCGIFDEBUG :
396             if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) {
397                 *(int *)mp->b_cont->b_wptr =
398                     (unsigned)(p->pai_flags & PAI_FLAGS_ALL_DEBUG)
399                         / PAI_FLAGS_DEBUG |
400                     (p->pai_flags & PAI_FLAGS_HIBITS);
401                 mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
402                 goto iocack;
403             }
404             i->ioc_error = ENOSR;
405             goto iocnak;
406
407         case SIOCSIFDEBUG :
408             if ((i->ioc_count != TRANSPARENT) &&
409                 (i->ioc_count != sizeof(int))) {
410                 i->ioc_error = EINVAL;
411                 goto iocnak;    /* ugh, goto */
412             }
413             flags = *(int *)mp->b_cont->b_rptr;
414             DLOG("ppp_async: SIFIFDEBUG %x\n", flags);
415             p->pai_flags &= ~PAI_FLAGS_ALL_DEBUG | PAI_FLAGS_HIBITS;
416             p->pai_flags |= ((unsigned) flags * PAI_FLAGS_DEBUG)
417                 & PAI_FLAGS_ALL_DEBUG;
418             i->ioc_count = 0;
419             goto iocack;
420
421         iocack:;
422             mp->b_datap->db_type = M_IOCACK;
423             qreply(q,mp);
424             break;
425         iocnak:;
426             i->ioc_count = 0;
427             mp->b_datap->db_type = M_IOCNAK;
428             qreply(q, mp);
429             break;
430         default:                                /* unknown IOCTL call */
431             putnext(q,mp);              /* pass it along */
432         }
433         break;
434
435     default:
436         putnext(q, mp); /* don't know what to do with this, so send it along*/
437     }
438 }
439
440 static int
441 ppp_async_wsrv(q)
442     queue_t     *q;
443 {
444     register u_char     *cp, *wp;
445     register PAI        *p;
446     register u_short    fcs;
447     register mblk_t     *mp, *m0;
448     mblk_t      *cop, *outgoing;
449     int proto, len, olen, c;
450
451     p = (PAI *) q->q_ptr;
452
453     while ((mp = getq(q)) != NULL) {
454         /*
455          * we can only get M_DATA types into our Queue,
456          * due to our Put function
457          */
458         if (!canput(q->q_next)) {
459             putbq(q, mp);
460             return;
461         }
462
463         /* at least a header required */
464         len = msgdsize(mp);
465         if (len < PPP_HDRLEN
466             || (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
467                 && !pullupmsg(mp, PPP_HDRLEN))) {       
468             freemsg(mp);                /* discard the message */
469             DLOG("ppp_async: short message (%d)\n", len);
470             /* indicate output err */
471             putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR);
472             continue;
473         }
474
475         /* Do address/control and protocol compression */
476         proto = (mp->b_rptr[2] << 8) + mp->b_rptr[3];
477         if (p->pai_flags & PAI_FLAGS_COMPAC && proto != PPP_LCP
478             && mp->b_rptr[0] == PPP_ALLSTATIONS && mp->b_rptr[1] == PPP_UI) {
479             mp->b_rptr += 2;
480             if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff)
481                 ++mp->b_rptr;
482         } else if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff) {
483             mp->b_rptr[2] = mp->b_rptr[1];
484             mp->b_rptr[1] = mp->b_rptr[0];
485             ++mp->b_rptr;
486         }
487
488         m0 = mp;                /* remember first message block */
489         fcs = PPP_INITFCS;
490
491         /*
492          * Estimate the required buffer length as 1.25 * message length
493          * to allow for escaped characters.  If this isn't enough, we
494          * allocate another buffer later.
495          */
496         olen = len + (len >> 2) + 5;
497         if (olen < 32)
498             olen = 32;
499         else if (olen > 2048)
500             olen = 2048;
501         outgoing = cop = allocb(olen, BPRI_MED);
502         if (outgoing == NULL) {
503             DLOG("allocb(%d) failed!\n", olen);
504             /* should do something tricky here */
505             goto nobuffs;
506         }
507         wp = cop->b_wptr;
508
509         /* Put the initial flag in (we'll take it out later if we don't
510            need it). */
511         *wp++ = PPP_FLAG;
512         --olen;
513
514 #define SPECIAL(p, c)   (p->pai_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
515
516         /*
517          * Copy the message to the output block, escaping characters
518          * as needed.
519          */
520         while (mp) {
521             for (cp = mp->b_rptr; cp < mp->b_wptr; ) {
522                 c = *cp++;
523                 if (olen < 2) {
524                     /* grab another message block and put it on the end */
525                     cop->b_wptr = wp;
526                     olen = 256;
527                     cop = allocb(olen, BPRI_MED);
528                     if (cop == NULL)
529                         goto nobuffs;
530                     linkb(outgoing, cop);
531                     wp = cop->b_wptr;
532                 }
533                 if (SPECIAL(p, c)) {
534                     *wp++ = PPP_ESCAPE;
535                     *wp++ = c ^ PPP_TRANS;
536                     olen -= 2;
537                 } else {
538                     *wp++ = c;
539                     --olen;
540                 }
541                 fcs = PPP_FCS(fcs, c);
542             }
543             mp = mp->b_cont; /* look at the next block */
544         }                                       /* end while(mp) */
545
546         /*
547          * Add the FCS and the trailing flag.
548          */
549         if (olen < 5) {
550             /* grab another message block for FCS and trailing flag */
551             cop->b_wptr = wp;
552             cop = allocb(5, BPRI_MED);
553             if (cop == NULL)
554                 goto nobuffs;
555             linkb(outgoing, cop);
556             wp = cop->b_wptr;
557         }
558         fcs ^= 0xffff;                          /* XOR the resulting FCS */
559         c = fcs & 0xff;
560         if (SPECIAL(p, c)) {
561             *wp++ = PPP_ESCAPE;
562             *wp++ = c ^ PPP_TRANS;
563         } else
564             *wp++ = c;
565         c = fcs >> 8;
566         if (SPECIAL(p, c)) {
567             *wp++ = PPP_ESCAPE;
568             *wp++ = c ^ PPP_TRANS;
569         } else
570             *wp++  = c;
571         *wp++ = PPP_FLAG;       /* add trailing PPP_FLAG */
572
573         cop->b_wptr = wp;
574         freemsg(m0);
575
576         /*
577          * now we check to see if the lower queue has entries, if so,
578          * we assume that we don't need a leading PPP_FLAG because
579          * these packets will be sent back to back.
580          */
581         if (qsize(q->q_next) > 0) {
582             /* entries in next queue, remove the leading PPP_FLAG */
583             ++outgoing->b_rptr;
584         }
585
586 #if DEBUGS
587         if (p->pai_flags & PAI_FLAGS_LOG_OUTPKT)
588             ppp_dump_frame(p, outgoing, " sent output");
589 #endif
590         putnext(q, outgoing);
591         continue;
592
593     nobuffs:    /* well, we ran out of memory somewhere */
594         if (outgoing)
595             freemsg(outgoing);          /* throw away what we have already */
596         putbq(q, m0);                   /* put back the original message */
597         putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR);
598         qenable(q);                     /* reschedule ourselves for later */
599         return;
600     } /* end while(getq()) */
601 }       /* end function */                                      
602
603 static int
604 ppp_async_rput(q, mp)
605     queue_t *q;
606     register mblk_t *mp;
607 {
608     switch (mp->b_datap->db_type) {
609     
610     case M_FLUSH:
611         if(*mp->b_rptr & FLUSHR)
612             flushq(q, FLUSHDATA);
613         putnext(q, mp);         /* send it along too */
614         break;
615     
616     case M_DATA:
617         putq(q, mp);            /* queue it for my service routine */
618         break;
619     
620     default:
621         putnext(q,mp);  /* don't know what to do with this, so send it along */
622     }
623 }
624
625 static u_int32_t paritytab[8] = {
626     0x96696996, 0x69969669, 0x69969669, 0x96696996,
627     0x69969669, 0x96696996, 0x96696996, 0x69969669,
628 };
629
630 static int
631 ppp_async_rsrv(q)
632     queue_t     *q;
633 {
634     register mblk_t *mp, *bp;
635     register PAI        *p;
636     register u_char     *cp,c;
637     mblk_t      *m0;
638     register u_char *wptr;
639     int bcount;
640   
641     p = (PAI *) q->q_ptr;
642
643 #define INPUT_ERROR(q)  putctl1(q, M_CTL, IF_INPUT_ERROR)
644 #define STUFF_CHAR(p,c) (*wptr++ = (c), (p)->pai_buffcount++)
645 #define FLUSHEM(q, p)   (INPUT_ERROR(q), (p)->pai_flags |= PAI_FLAGS_FLUSH)
646   
647     while ((mp = getq(q)) != NULL) {
648         /* we can only get M_DATA types into our Queue,
649            due to our Put function */
650         if (!canput(q->q_next)) {
651             putbq(q, mp);
652             return;
653         }
654         m0 = mp;        /* remember first message block */
655         for (; mp != NULL; mp = mp->b_cont) {   /* for each message block */
656             cp = mp->b_rptr;
657             while (cp < mp->b_wptr) {
658                 c = *cp++;
659
660                 /* Accumulate info to help with detecting
661                    non 8-bit clean links. */
662                 if (c & 0x80)
663                     p->pai_flags |= PAI_FLAGS_B7_1;
664                 else
665                     p->pai_flags |= PAI_FLAGS_B7_0;
666                 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
667                     p->pai_flags |= PAI_FLAGS_PAR_ODD;
668                 else
669                     p->pai_flags |= PAI_FLAGS_PAR_EVEN;
670
671                 /* Throw out chars in the receive asyncmap. */
672                 if (c < 0x20 && (p->pai_rasyncmap & (1 << c)))
673                     continue;
674
675                 /* A flag marks the end of a frame. */
676                 if (c == PPP_FLAG) {
677                     bp = p->pai_buffer;
678                     bcount = p->pai_buffcount;
679                     p->pai_buffer = NULL;
680                     p->pai_buffcount = 0;
681
682                     /* if the escape indicator is set, then we have
683                        seen the packet abort sequence "}~". */
684                     if (p->pai_flags & (PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH)) {
685                         if ((p->pai_flags & PAI_FLAGS_FLUSH) == 0)
686                             DLOG("ppp_async: packet abort\n", 0);
687                         p->pai_flags &= ~(PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH);
688                         if (bp)
689                             freemsg(bp);
690                         continue;
691                     }
692
693                     if (bcount > PPP_FCSLEN) {  /* discard FCS */
694                         adjmsg(bp, -PPP_FCSLEN);
695                         bcount -= PPP_FCSLEN;
696                     }
697
698                     if (bcount < PPP_HDRLEN) {
699                         if (bcount) {
700                             INPUT_ERROR(q);
701                             DLOG("ppp_async: short input packet (%d)\n",
702                                  bcount);
703                         }
704                         if (bp)
705                             freemsg(bp);
706                         continue;
707                     }
708
709                     if (bp) {
710                         if (p->pai_fcs == PPP_GOODFCS) {
711 #if DEBUGS
712                             if (p->pai_flags & PAI_FLAGS_LOG_INPKT)
713                                 ppp_dump_frame(p, bp, " got input");
714 #endif /*DEBUGS*/
715                             putnext(q, bp);
716                         }
717                         else {
718                             INPUT_ERROR(q);
719                             freemsg(bp);
720                             DLOG("ppp_async: FCS Error\n", 0);
721                         }
722                     }
723                     continue;
724                 }
725
726                 /* here c != PPP_FLAG */
727                 if (p->pai_flags & PAI_FLAGS_FLUSH) {
728                     while (cp < mp->b_wptr && *cp != PPP_FLAG)
729                         ++cp;
730                     continue;
731                 }
732
733                 if (p->pai_flags & PAI_FLAGS_ESCAPED) {
734                     p->pai_flags &= ~PAI_FLAGS_ESCAPED; /* clear esc flag */
735                     c ^= PPP_TRANS;
736                 } else if (c == PPP_ESCAPE) {
737                     if (cp >= mp->b_wptr || (c = *cp) == PPP_FLAG
738                         || c < 0x20 && (p->pai_rasyncmap & (1 << c))) {
739                         p->pai_flags |= PAI_FLAGS_ESCAPED;
740                         continue;
741                     }
742                     c ^= PPP_TRANS;
743                     ++cp;
744                 }
745
746                 /* here we check to see if we have a buffer.
747                    If we don't, we assume that this is the first char
748                    for the buffer, and we allocb one */
749         
750                 if (!p->pai_buffer) {
751                     /* we allocate buffer chains in blocks of ALLOCBSIZE */
752           
753                     if (!(p->pai_buffer = allocb(ALLOCBSIZE, BPRI_MED))) {
754                         FLUSHEM(q, p);
755                         continue;
756                         /* if we don't get a buffer, is there some way
757                            to recover and requeue later? rather than flushing
758                            the current packet... ? */
759                     }
760                     p->pai_bufftail = p->pai_buffer;
761                 }
762                 wptr = p->pai_bufftail->b_wptr;
763
764                 if (!p->pai_buffcount) {
765                     p->pai_fcs = PPP_INITFCS;
766                     if (c != PPP_ALLSTATIONS) {
767                         if (p->pai_flags & PAI_FLAGS_RCV_COMPAC) {
768                             STUFF_CHAR(p, PPP_ALLSTATIONS);
769                             STUFF_CHAR(p, PPP_UI);
770                         }
771                         else {
772                             DLOG("ppp_async: missed ALLSTATIONS (0xff), got 0x%x\n", c);
773                             FLUSHEM(q, p);
774                             continue;
775                         }
776                     }
777                 } /* end if !p->pai_buffcount */
778
779                 if (p->pai_buffcount == 1 && c != PPP_UI) {
780                     DLOG("ppp_async: missed UI (0x3), got 0x%x\n", c);
781                     FLUSHEM(q,p);
782                     continue;
783                 }
784
785                 if (p->pai_buffcount == 2 && (c & 1) == 1) {
786                     if (p->pai_flags & PAI_FLAGS_RCV_COMPPROT)
787                         STUFF_CHAR(p, 0);
788                     else {
789                         DLOG("ppp_async: bad protocol high byte %x\n", c);
790                         FLUSHEM(q, p);
791                         continue;
792                     }
793                 }
794
795                 if (p->pai_buffcount == 3 && (c & 1) == 0) {
796                     DLOG("ppp_async: bad protocol low byte %x\n", c);
797                     FLUSHEM(q, p);
798                     continue;
799                 }
800
801                 if (p->pai_buffcount >= p->pai_buffsize) {      /* overrun */
802                     DLOG("ppp_async: too many chars in input buffer %d\n",
803                          p->pai_buffcount);
804                     FLUSHEM(q, p);
805                     continue;
806                 }
807
808                 /* determine if we have enough space in the buffer */
809                 if (wptr >= p->pai_bufftail->b_datap->db_lim) {
810                     p->pai_bufftail->b_wptr = wptr;
811                     if (!(p->pai_bufftail = allocb(ALLOCBSIZE, BPRI_MED))) {
812                         DLOG("ppp_async: couldn't get buffer for tail\n", 0);
813                         FLUSHEM(q, p);  /* discard all of it */
814                         continue;
815                     }
816                     linkb(p->pai_buffer, p->pai_bufftail);
817                     wptr = p->pai_bufftail->b_wptr;
818                 }
819
820                 STUFF_CHAR(p, c);
821                 p->pai_fcs = PPP_FCS(p->pai_fcs, c);
822
823                 if (p->pai_buffcount >= PPP_HDRLEN) {
824                     while (cp < mp->b_wptr
825                            && wptr < p->pai_bufftail->b_datap->db_lim
826                            && (c = *cp) != PPP_FLAG && c != PPP_ESCAPE) {
827                         if (c >= 0x20 || (p->pai_rasyncmap & (1 << c)) == 0) {
828                             STUFF_CHAR(p, c);
829                             p->pai_fcs = PPP_FCS(p->pai_fcs, c);
830                         }
831                         ++cp;
832                     }
833                 }
834
835                 p->pai_bufftail->b_wptr = wptr;
836
837             } /* end while cp < wptr */
838         }       /* end for each block */
839         /* discard this message now */
840         freemsg(m0);
841     }   /* end while  getq */
842   
843 }
844
845 #if DEBUGS
846 /*
847  * here is where we will dump out a frame in hex using the log() 
848  * function if ppp_async_input_debug is non-zero. As this function is
849  * a pig, we only print up to the number of bytes specified by the value of
850  * the ppp_async_max_dump_bytes variable so as to not cause too many
851  * timeouts.   <gmc@quotron.com> 
852  */
853
854 static void
855 ppp_dump_frame(p, mptr, msg)
856     register PAI *p;
857     register mblk_t *mptr;
858     char *msg;
859 {
860     register u_char *rptr;
861     register u_int i, mlen, frame_length;
862     char buf[2*MAX_DUMP_BYTES+4];       /* tmp buffer */
863     char *bp = buf;
864     static char digits[] = "0123456789abcdef";
865
866     frame_length = i = msgdsize(mptr);
867     bsdlog(LOG_INFO, "ppp_async%d:%s frame of %d bytes\n", p - pai,
868         msg, frame_length); 
869     rptr = mptr->b_rptr; /* get pointer to beginning  */
870     mlen = mptr->b_wptr - rptr; /* get length of this dblock */
871
872     /* only dump up to MAX_DUMP_BYTES */
873     if (i > ppp_async_max_dump_bytes)
874         i = ppp_async_max_dump_bytes;   
875
876     while (i--) {                       /* convert to ascii hex */
877         while (mlen == 0) {             /* get next dblock */
878             mptr = mptr->b_cont;
879             if (mptr) { /* are we done? */
880                 rptr = mptr->b_rptr;    /* nope, get next dblock */
881                 mlen = mptr->b_wptr - rptr;
882             }
883             else {                      /* no more dblocks */
884                 if (i != 0)
885                     bsdlog(LOG_ERR, "ppp_async: ran out of data! (this shouldn't happen\n");
886                 break;
887             }
888         }
889         --mlen;
890         *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
891         *bp++ = digits[*rptr++ & 0xf];
892     }
893
894     /* add a '>' to show that frame was truncated*/
895     if (ppp_async_max_dump_bytes < frame_length)
896         *bp++ = '>';
897     *bp = 0;
898     bsdlog(LOG_INFO,"ppp_async: %s\n", buf); 
899 }
900 #endif /* DEBUGS */
901
902 #endif /* NUM_PPP > 0 */