Rest of IPV6 merge which got lost somehow, plus some minor fixes.
[mpls-ppp.git] / aix4 / ppp_async.c
blobd079e3f87037d806dc18ae33d7ec909b8c11b5e6
1 /*
2 ppp_async.c - Streams async functions Also does FCS
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
8 $Id: ppp_async.c,v 1.3 1995/04/26 04:15:48 paulus Exp $
9 */
11 #include <sys/types.h>
13 #ifndef PPP_VD
14 #include "ppp.h"
15 #endif
17 #if NUM_PPP > 0
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>
35 #include <net/ppp_defs.h>
36 #include <net/ppp_str.h>
38 /* how big of a buffer block to allocate for each chunk of the input chain */
39 #define ALLOCBSIZE 64
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)
45 int ppp_async_max_dump_bytes = 28;
46 #define MAX_DUMP_BYTES 1504
48 static void ppp_dump_frame();
50 #else
51 #define DLOG(s) {}
52 #endif
54 static int ppp_async_open(), ppp_async_close(), ppp_async_rput(),
55 ppp_async_wput(), ppp_async_wsrv(), ppp_async_rsrv();
57 static struct module_info minfo ={
58 0xabcd,"ppp_async",0, INFPSZ, 16384, 4096
61 static struct qinit r_init = {
62 ppp_async_rput, ppp_async_rsrv, ppp_async_open, ppp_async_close,
63 NULL, &minfo, NULL
65 static struct qinit w_init = {
66 ppp_async_wput, ppp_async_wsrv, ppp_async_open, ppp_async_close,
67 NULL, &minfo, NULL
69 struct streamtab ppp_asyncinfo = {
70 &r_init, &w_init, NULL, NULL
74 * FCS lookup table as calculated by genfcstab.
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
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 */
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
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
137 typedef struct ppp_async_info PAI;
139 static PAI pai[NUM_PPP*2]; /* our private cache of async ctrl structs */
141 static strconf_t pppasync_conf = {
142 "pppasync", &ppp_asyncinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0
145 int ppp_async_load(int cmd, struct uio *uiop)
147 int rc;
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;
160 return(rc);
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;
171 register PAI *p;
172 register int x;
173 int s;
175 /* only let the superuser or setuid root ppl open this module */
176 if (!suser()) {
177 return(EPERM);
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);
187 p = &pai[x];
188 DLOG("ppp_async%d: opening\n",x);
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;
199 else {
200 p = (PAI *) q->q_ptr;
201 DLOG("ppp_async%d: reopen\n", p - pai);
203 return(0);
206 static int
207 ppp_async_close(q)
208 queue_t *q; /* queue info */
210 int s;
211 register PAI *p;
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;
220 DLOG("ppp_async%d: closing\n", p - pai);
222 return(0);
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.
229 SIOC{G,S}IF{,R,X}ASYNCMAP are handled here.
231 SIOCSIFCOMPAC and SIOCSIFCOMPPROT are both handled here.
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.
237 static int
238 ppp_async_wput(q, mp)
239 queue_t *q;
240 register mblk_t *mp;
242 register struct iocblk *i;
243 register PAI *p;
244 int x, flags;
246 switch (mp->b_datap->db_type) {
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);
257 break;
259 case M_FLUSH :
260 if (*mp->b_rptr & FLUSHW)
261 flushq(q, FLUSHDATA);
262 putnext(q, mp); /* send it along too */
263 break;
265 case M_DATA :
266 putq(q, mp); /* queue it for my service routine */
267 break;
269 case M_IOCTL :
270 i = (struct iocblk *) mp->b_rptr;
271 p = (PAI *) q->q_ptr;
272 switch ((unsigned int)i->ioc_cmd) {
274 case SIOCSIFCOMPAC : /* enable or disable AC compression */
275 if (i->ioc_count != TRANSPARENT) {
276 i->ioc_error = EINVAL;
277 goto iocnak;
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;
289 case SIOCSIFCOMPPROT: /* enable or disable PROT compression */
290 if (i->ioc_count != TRANSPARENT) {
291 i->ioc_error = EINVAL;
292 goto iocnak;
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;
305 case SIOCSIFMRU :
306 if ((i->ioc_count != TRANSPARENT) &&
307 (i->ioc_count != sizeof(int))) {
308 i->ioc_error = EINVAL;
309 goto iocnak;
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;
319 p->pai_buffsize = x;
320 i->ioc_count = 0;
321 goto iocack;
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;
330 i->ioc_error = ENOSR;
331 goto iocnak;
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;
339 i->ioc_error = ENOSR;
340 goto iocnak;
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 */
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;
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;
359 i->ioc_error = ENOSR;
360 goto iocnak;
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 */
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;
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;
379 i->ioc_error = ENOSR;
380 goto iocnak;
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 */
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;
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;
404 i->ioc_error = ENOSR;
405 goto iocnak;
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 */
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;
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 */
433 break;
435 default:
436 putnext(q, mp); /* don't know what to do with this, so send it along*/
440 static int
441 ppp_async_wsrv(q)
442 queue_t *q;
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;
451 p = (PAI *) q->q_ptr;
453 while ((mp = getq(q)) != NULL) {
455 * we can only get M_DATA types into our Queue,
456 * due to our Put function
458 if (!canput(q->q_next)) {
459 putbq(q, mp);
460 return;
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;
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;
488 m0 = mp; /* remember first message block */
489 fcs = PPP_INITFCS;
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.
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;
507 wp = cop->b_wptr;
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;
514 #define SPECIAL(p, c) (p->pai_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
517 * Copy the message to the output block, escaping characters
518 * as needed.
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;
533 if (SPECIAL(p, c)) {
534 *wp++ = PPP_ESCAPE;
535 *wp++ = c ^ PPP_TRANS;
536 olen -= 2;
537 } else {
538 *wp++ = c;
539 --olen;
541 fcs = PPP_FCS(fcs, c);
543 mp = mp->b_cont; /* look at the next block */
544 } /* end while(mp) */
547 * Add the FCS and the trailing flag.
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;
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 */
573 cop->b_wptr = wp;
574 freemsg(m0);
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.
581 if (qsize(q->q_next) > 0) {
582 /* entries in next queue, remove the leading PPP_FLAG */
583 ++outgoing->b_rptr;
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;
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 */
603 static int
604 ppp_async_rput(q, mp)
605 queue_t *q;
606 register mblk_t *mp;
608 switch (mp->b_datap->db_type) {
610 case M_FLUSH:
611 if(*mp->b_rptr & FLUSHR)
612 flushq(q, FLUSHDATA);
613 putnext(q, mp); /* send it along too */
614 break;
616 case M_DATA:
617 putq(q, mp); /* queue it for my service routine */
618 break;
620 default:
621 putnext(q,mp); /* don't know what to do with this, so send it along */
625 static u_int32_t paritytab[8] = {
626 0x96696996, 0x69969669, 0x69969669, 0x96696996,
627 0x69969669, 0x96696996, 0x96696996, 0x69969669,
630 static int
631 ppp_async_rsrv(q)
632 queue_t *q;
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;
641 p = (PAI *) q->q_ptr;
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)
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;
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++;
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;
671 /* Throw out chars in the receive asyncmap. */
672 if (c < 0x20 && (p->pai_rasyncmap & (1 << c)))
673 continue;
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;
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;
693 if (bcount > PPP_FCSLEN) { /* discard FCS */
694 adjmsg(bp, -PPP_FCSLEN);
695 bcount -= PPP_FCSLEN;
698 if (bcount < PPP_HDRLEN) {
699 if (bcount) {
700 INPUT_ERROR(q);
701 DLOG("ppp_async: short input packet (%d)\n",
702 bcount);
704 if (bp)
705 freemsg(bp);
706 continue;
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);
717 else {
718 INPUT_ERROR(q);
719 freemsg(bp);
720 DLOG("ppp_async: FCS Error\n", 0);
723 continue;
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;
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;
742 c ^= PPP_TRANS;
743 ++cp;
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 */
750 if (!p->pai_buffer) {
751 /* we allocate buffer chains in blocks of ALLOCBSIZE */
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... ? */
760 p->pai_bufftail = p->pai_buffer;
762 wptr = p->pai_bufftail->b_wptr;
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);
771 else {
772 DLOG("ppp_async: missed ALLSTATIONS (0xff), got 0x%x\n", c);
773 FLUSHEM(q, p);
774 continue;
777 } /* end if !p->pai_buffcount */
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;
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;
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;
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;
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;
816 linkb(p->pai_buffer, p->pai_bufftail);
817 wptr = p->pai_bufftail->b_wptr;
820 STUFF_CHAR(p, c);
821 p->pai_fcs = PPP_FCS(p->pai_fcs, c);
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);
831 ++cp;
835 p->pai_bufftail->b_wptr = wptr;
837 } /* end while cp < wptr */
838 } /* end for each block */
839 /* discard this message now */
840 freemsg(m0);
841 } /* end while getq */
845 #if DEBUGS
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>
854 static void
855 ppp_dump_frame(p, mptr, msg)
856 register PAI *p;
857 register mblk_t *mptr;
858 char *msg;
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";
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 */
872 /* only dump up to MAX_DUMP_BYTES */
873 if (i > ppp_async_max_dump_bytes)
874 i = ppp_async_max_dump_bytes;
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;
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;
889 --mlen;
890 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
891 *bp++ = digits[*rptr++ & 0xf];
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);
900 #endif /* DEBUGS */
902 #endif /* NUM_PPP > 0 */