From c1a66729914c44d5171da98ef4e2f73332457518 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 5 Dec 1994 00:29:21 +0000 Subject: [PATCH 1/1] Initial revision --- aix4/Makefile | 51 +++ aix4/ppp_async.c | 887 ++++++++++++++++++++++++++++++++++++ aix4/ppp_comp.c | 437 ++++++++++++++++++ aix4/ppp_if.c | 1123 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 2498 insertions(+) create mode 100644 aix4/Makefile create mode 100644 aix4/ppp_async.c create mode 100644 aix4/ppp_comp.c create mode 100644 aix4/ppp_if.c diff --git a/aix4/Makefile b/aix4/Makefile new file mode 100644 index 0000000..8c72052 --- /dev/null +++ b/aix4/Makefile @@ -0,0 +1,51 @@ +# +# Makefile for AIX 4.1 +# +# +# $Id: Makefile,v 1.1 1994/12/05 00:29:21 paulus Exp $ +# +#ifndef DRIVERS +DRIVERS=/usr/lib/drivers +#endif + +CC=xlc +IFLAGS = -I.. +DFLAGS = -D_KERNEL -DINET -DPPP_VD -DNUM_PPP=5 -DDEBUGS -DPPP_STATS -DVJC +CFLAGS = $(DFLAGS) $(IFLAGS) + +KIMP = -bI:/lib/pse.exp -bI:/lib/kernex.exp -bI:/lib/syscalls.exp +NETIMP = -bI:/lib/netinet.exp +KLIBS = /lib/libsys.a /lib/libcsys.a + + +OBJ = vjcompress.o ppp_if.o ppp_async.o bsd-comp.o ppp_comp.o + +all: ppp_if ppp_async ppp_comp + +ppp_if: ppp_if.o vjcompress.o + ld -o ppp_if ppp_if.o -e ppp_load -bE:ppp_if.exp vjcompress.o ${KIMP} ${NETIMP} ${KLIBS} + +ppp_async: ppp_async.o + ld -o ppp_async ppp_async.o -e ppp_async_load -bE:ppp_async.exp ${KIMP} ${NETIMP} ${KLIBS} + +ppp_comp: ppp_comp.o bsd-comp.o + ld -o ppp_comp ppp_comp.o -e pppcomp_load bsd-comp.o ${KIMP} ${NETIMP} ${KLIBS} + +vjcompress.o: vjcompress.c +bsd-comp.o: bsd-comp.c +ppp_if.o: ppp_if.c +ppp_async.o: ppp_async.c +ppp_comp.o: ppp_comp.c + +install: all + install -f ${DRIVERS} -M 500 ppp_if + install -f ${DRIVERS} -M 500 ppp_async + install -f ${DRIVERS} -M 500 ppp_comp + grep "strload -m ${DRIVERS}/ppp_if" /etc/rc.tcpip || { \ + echo strload -m ${DRIVERS}/ppp_if; \ + echo strload -m ${DRIVERS}/ppp_async; \ + echo strload -m ${DRIVERS}/ppp_comp; \ + } >>/etc/rc.tcpip + +clean: + rm -f $(OBJ) ppp_if ppp_async ppp_comp diff --git a/aix4/ppp_async.c b/aix4/ppp_async.c new file mode 100644 index 0000000..c932fd3 --- /dev/null +++ b/aix4/ppp_async.c @@ -0,0 +1,887 @@ +/* + ppp_async.c - Streams async functions Also does FCS + + Copyright (C) 1990 Brad K. Clements, All Rights Reserved + fcstab and some ideas nicked from if_ppp.c from cmu. + See copyright notice in if_ppp.h and NOTES + + $Id: ppp_async.c,v 1.1 1994/12/05 00:29:21 paulus Exp $ +*/ + +#include + +#ifndef PPP_VD +#include "ppp.h" +#endif + +#if NUM_PPP > 0 + +#define STREAMS 1 +#define DEBUGS 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* how big of a buffer block to allocate for each chunk of the input chain */ +#define ALLOCBSIZE 64 + +#ifdef DEBUGS +#include +#define DLOG(s,a) if (p->pai_flags&PAI_FLAGS_DEBUG) bsdlog(LOG_INFO, s, a) + +int ppp_async_max_dump_bytes = 28; +#define MAX_DUMP_BYTES 1504 + +static void ppp_dump_frame(); + +#else +#define DLOG(s) {} +#endif + +static int ppp_async_open(), ppp_async_close(), ppp_async_rput(), + ppp_async_wput(), ppp_async_wsrv(), ppp_async_rsrv(); + +static struct module_info minfo ={ + 0xabcd,"ppp_async",0, INFPSZ, 16384, 4096 +}; + +static struct qinit r_init = { + ppp_async_rput, ppp_async_rsrv, ppp_async_open, ppp_async_close, + NULL, &minfo, NULL +}; +static struct qinit w_init = { + ppp_async_wput, ppp_async_wsrv, ppp_async_open, ppp_async_close, + NULL, &minfo, NULL +}; +struct streamtab ppp_asyncinfo = { + &r_init, &w_init, NULL, NULL +}; + +/* + * FCS lookup table as calculated by genfcstab. + */ +static u_short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + + +struct ppp_async_info { + u_int pai_flags; + int pai_buffsize; /* how big of an input buffer to alloc */ + int pai_buffcount; /* how many chars currently in input buffer */ + u_short pai_fcs; /* the current fcs */ + mblk_t *pai_buffer; /* pointer to the current buffer list */ + mblk_t *pai_bufftail; /* pointer to the current input block */ + ext_accm pai_asyncmap; /* current outgoing asyncmap */ + u_long pai_rasyncmap; /* current receive asyncmap */ +}; + +/* Values for pai_flags */ +#define PAI_FLAGS_INUSE 0x1 +#define PAI_FLAGS_FLUSH 0x2 +#define PAI_FLAGS_ESCAPED 0x4 +#define PAI_FLAGS_COMPPROT 0x8 +#define PAI_FLAGS_COMPAC 0x10 +#define PAI_FLAGS_RCV_COMPPROT 0x20 +#define PAI_FLAGS_RCV_COMPAC 0x40 + +#define PAI_FLAGS_DEBUG 0x1000 +#define PAI_FLAGS_LOG_INPKT 0x2000 +#define PAI_FLAGS_LOG_OUTPKT 0x4000 +#define PAI_FLAGS_ALL_DEBUG 0x7000 + +typedef struct ppp_async_info PAI; + +static PAI pai[NUM_PPP*2]; /* our private cache of async ctrl structs */ + +static strconf_t pppasync_conf = { + "pppasync", &ppp_asyncinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0 +}; + +int ppp_async_load(int cmd, struct uio *uiop) +{ + int rc; + + switch (cmd) { + case CFG_INIT: + rc = str_install(STR_LOAD_MOD, &pppasync_conf); + break; + case CFG_TERM: + rc = str_install(STR_UNLOAD_MOD, &pppasync_conf); + break; + default: + rc = EINVAL; + break; + } + return(rc); +} + +/* open might fail if we don't have any more pai elements left free */ +static int +ppp_async_open(q, dev, flag, sflag) + queue_t *q; + dev_t dev; + int flag; + int sflag; +{ + register PAI *p; + register int x; + int s; + + /* only let the superuser or setuid root ppl open this module */ + if (!suser()) { + return(EPERM); + } + + if (!q->q_ptr) { + for (x=0; x < NUM_PPP; x++) /* search for an empty PAI */ + if (!(pai[x].pai_flags & PAI_FLAGS_INUSE)) + break; + if (x == NUM_PPP) { /* all buffers in use */ + return(ENOBUFS); + } + p = &pai[x]; + DLOG("ppp_async%d: opening\n",x); + + /* initialize the unit to default values */ + WR(q)->q_ptr = q->q_ptr = (caddr_t) p; + bzero(p, sizeof(*p)); + p->pai_flags = PAI_FLAGS_INUSE | PAI_FLAGS_RCV_COMPAC + | PAI_FLAGS_RCV_COMPPROT; + p->pai_asyncmap[0] = 0xffffffff; /* default async map */ + p->pai_asyncmap[3] = 0x60000000; /* escape 7d, 7e */ + p->pai_buffsize = PPP_MTU + PPP_HDRLEN + PPP_FCSLEN; + } + else { + p = (PAI *) q->q_ptr; + DLOG("ppp_async%d: reopen\n", p - pai); + } + return(0); +} + +static int +ppp_async_close(q) + queue_t *q; /* queue info */ +{ + int s; + register PAI *p; + + if ((p = (PAI *) q->q_ptr) != NULL) { + p->pai_flags = 0; /* clear all flags */ + if (p->pai_buffer) { + /* currently receiving some chars, discard the buffer */ + freemsg(p->pai_buffer); + p->pai_buffer = NULL; + } + DLOG("ppp_async%d: closing\n", p - pai); + } + return(0); +} + + +/* M_IOCTL processing is performed at this level. There is some + weirdness here, but I couldn't think of an easier way to handle it. + + SIOC{G,S}IF{,R,X}ASYNCMAP are handled here. + + SIOCSIFCOMPAC and SIOCSIFCOMPPROT are both handled here. + + SIOCSIFMRU and SIOCGIFMRU (Max Receive Unit) are both handled here. + Rather than using the MTU to set the MRU, we have a seperate IOCTL for it. +*/ + +static int +ppp_async_wput(q, mp) + queue_t *q; + register mblk_t *mp; +{ + register struct iocblk *i; + register PAI *p; + int x, flags; + + switch (mp->b_datap->db_type) { + + case M_FLUSH : + if (*mp->b_rptr & FLUSHW) + flushq(q, FLUSHDATA); + putnext(q, mp); /* send it along too */ + break; + + case M_DATA : + putq(q, mp); /* queue it for my service routine */ + break; + + case M_IOCTL : + i = (struct iocblk *) mp->b_rptr; + p = (PAI *) q->q_ptr; + switch ((unsigned int)i->ioc_cmd) { + + case SIOCSIFCOMPAC : /* enable or disable AC compression */ + if (i->ioc_count != TRANSPARENT) { + i->ioc_error = EINVAL; + goto iocnak; + } + x = *(u_int *) mp->b_cont->b_rptr; + DLOG("ppp_async: SIFCOMPAC %d\n", x); + flags = (x & 2)? PAI_FLAGS_RCV_COMPAC: PAI_FLAGS_COMPAC; + if (x & 1) + p->pai_flags |= flags; + else + p->pai_flags &= ~flags; + i->ioc_count = 0; + goto iocack; + + case SIOCSIFCOMPPROT: /* enable or disable PROT compression */ + if (i->ioc_count != TRANSPARENT) { + i->ioc_error = EINVAL; + goto iocnak; + } + x = *(u_int *) mp->b_cont->b_rptr; + DLOG("ppp_async: SIFCOMPPROT %d\n", x); + flags = (x & 2)? PAI_FLAGS_RCV_COMPPROT: PAI_FLAGS_COMPPROT; + if (x & 1) + p->pai_flags |= flags; + else + p->pai_flags &= ~flags; + i->ioc_count = 0; + goto iocack; + + + case SIOCSIFMRU : + if ((i->ioc_count != TRANSPARENT) && + (i->ioc_count != sizeof(int))) { + i->ioc_error = EINVAL; + goto iocnak; + } + x = *(int *) mp->b_cont->b_rptr; + if (x < PPP_MTU) + x = PPP_MTU; + x += PPP_HDRLEN + PPP_FCSLEN; + if (x > 4096) { /* couldn't allocb something this big */ + i->ioc_error = EINVAL; + goto iocnak; + } + p->pai_buffsize = x; + i->ioc_count = 0; + goto iocack; + + case SIOCGIFMRU : + if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) { + *(int *) mp->b_cont->b_wptr = + p->pai_buffsize - (PPP_HDRLEN + PPP_FCSLEN); + mp->b_cont->b_wptr += i->ioc_count = sizeof(int); + goto iocack; + } + i->ioc_error = ENOSR; + goto iocnak; + + case SIOCGIFASYNCMAP : + if ((mp->b_cont = allocb(sizeof(u_long), BPRI_MED)) != NULL) { + *(u_long *) mp->b_cont->b_wptr = p->pai_asyncmap[0]; + mp->b_cont->b_wptr += i->ioc_count = sizeof(u_long); + goto iocack; + } + i->ioc_error = ENOSR; + goto iocnak; + + case SIOCSIFASYNCMAP : + if ((i->ioc_count != TRANSPARENT) && + (i->ioc_count != sizeof(u_long))) { + i->ioc_error = EINVAL; + goto iocnak; /* ugh, goto */ + } + p->pai_asyncmap[0] = *(u_long *) mp->b_cont->b_rptr; + DLOG("ppp_async: SIFASYNCMAP %lx\n", p->pai_asyncmap[0]); + i->ioc_count = 0; + goto iocack; + + case SIOCGIFRASYNCMAP : + if ((mp->b_cont = allocb(sizeof(u_long), BPRI_MED)) != NULL) { + *(u_long *) mp->b_cont->b_wptr = p->pai_rasyncmap; + mp->b_cont->b_wptr += i->ioc_count = sizeof(u_long); + goto iocack; + } + i->ioc_error = ENOSR; + goto iocnak; + + case SIOCSIFRASYNCMAP : + if ((i->ioc_count != TRANSPARENT) && + (i->ioc_count != sizeof(u_long))) { + i->ioc_error = EINVAL; + goto iocnak; /* ugh, goto */ + } + p->pai_rasyncmap = *(u_long *) mp->b_cont->b_rptr; + DLOG("ppp_async: SIFRASYNCMAP %lx\n", p->pai_rasyncmap); + i->ioc_count = 0; + goto iocack; + + case SIOCGIFXASYNCMAP : + if ((mp->b_cont = allocb(sizeof(ext_accm), BPRI_MED)) != NULL) { + bcopy(p->pai_asyncmap, mp->b_cont->b_wptr, sizeof(ext_accm)); + mp->b_cont->b_wptr += i->ioc_count = sizeof(ext_accm); + goto iocack; + } + i->ioc_error = ENOSR; + goto iocnak; + + case SIOCSIFXASYNCMAP : + if ((i->ioc_count != TRANSPARENT) && + (i->ioc_count != sizeof(ext_accm))) { + i->ioc_error = EINVAL; + goto iocnak; /* ugh, goto */ + } + bcopy(*mp->b_cont->b_rptr, p->pai_asyncmap, sizeof(ext_accm)); + p->pai_asyncmap[1] = 0; /* can't escape 20-3f */ + p->pai_asyncmap[2] &= ~0x40000000; /* can't escape 5e */ + p->pai_asyncmap[3] |= 0x60000000; /* must escape 7d, 7e */ + i->ioc_count = 0; + goto iocack; + + case SIOCGIFDEBUG : + if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) { + *(int *)mp->b_cont->b_wptr = + (unsigned)(p->pai_flags & PAI_FLAGS_ALL_DEBUG) + / PAI_FLAGS_DEBUG | + (p->pai_flags & PAI_FLAGS_HIBITS); + mp->b_cont->b_wptr += i->ioc_count = sizeof(int); + goto iocack; + } + i->ioc_error = ENOSR; + goto iocnak; + + case SIOCSIFDEBUG : + if ((i->ioc_count != TRANSPARENT) && + (i->ioc_count != sizeof(int))) { + i->ioc_error = EINVAL; + goto iocnak; /* ugh, goto */ + } + flags = *(int *)mp->b_cont->b_rptr; + DLOG("ppp_async: SIFIFDEBUG %x\n", flags); + p->pai_flags &= ~PAI_FLAGS_ALL_DEBUG | PAI_FLAGS_HIBITS; + p->pai_flags |= ((unsigned) flags * PAI_FLAGS_DEBUG) + & PAI_FLAGS_ALL_DEBUG; + i->ioc_count = 0; + goto iocack; + + iocack:; + mp->b_datap->db_type = M_IOCACK; + qreply(q,mp); + break; + iocnak:; + i->ioc_count = 0; + mp->b_datap->db_type = M_IOCNAK; + qreply(q, mp); + break; + default: /* unknown IOCTL call */ + putnext(q,mp); /* pass it along */ + } + break; + + default: + putnext(q, mp); /* don't know what to do with this, so send it along*/ + } +} + +static int +ppp_async_wsrv(q) + queue_t *q; +{ + register u_char *cp, *wp; + register PAI *p; + register u_short fcs; + register mblk_t *mp, *m0; + mblk_t *cop, *outgoing; + int proto, len, olen, c; + + p = (PAI *) q->q_ptr; + + while ((mp = getq(q)) != NULL) { + /* + * we can only get M_DATA types into our Queue, + * due to our Put function + */ + if (!canput(q->q_next)) { + putbq(q, mp); + return; + } + + /* at least a header required */ + len = msgdsize(mp); + if (len < PPP_HDRLEN + || (mp->b_wptr - mp->b_rptr < PPP_HDRLEN + && !pullupmsg(mp, PPP_HDRLEN))) { + freemsg(mp); /* discard the message */ + DLOG("ppp_async: short message (%d)\n", len); + /* indicate output err */ + putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR); + continue; + } + + /* Do address/control and protocol compression */ + proto = (mp->b_rptr[2] << 8) + mp->b_rptr[3]; + if (p->pai_flags & PAI_FLAGS_COMPAC && proto != PPP_LCP + && mp->b_rptr[0] == PPP_ALLSTATIONS && mp->b_rptr[1] == PPP_UI) { + mp->b_rptr += 2; + if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff) + ++mp->b_rptr; + } else if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff) { + mp->b_rptr[2] = mp->b_rptr[1]; + mp->b_rptr[1] = mp->b_rptr[0]; + ++mp->b_rptr; + } + + m0 = mp; /* remember first message block */ + fcs = PPP_INITFCS; + + /* + * Estimate the required buffer length as 1.25 * message length + * to allow for escaped characters. If this isn't enough, we + * allocate another buffer later. + */ + olen = len + (len >> 8) + 5; + if (olen < 32) + olen = 32; + else if (olen > 2048) + olen = 2048; + outgoing = cop = allocb(olen, BPRI_MED); + if (outgoing == NULL) { + DLOG("allocb(%d) failed!\n", olen); + /* should do something tricky here */ + goto nobuffs; + } + wp = cop->b_wptr; + + /* Put the initial flag in (we'll take it out later if we don't + need it). */ + *wp++ = PPP_FLAG; + --olen; + +#define SPECIAL(p, c) (p->pai_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) + + /* + * Copy the message to the output block, escaping characters + * as needed. + */ + while (mp) { + for (cp = mp->b_rptr; cp < mp->b_wptr; ) { + c = *cp++; + if (olen < 2) { + /* grab another message block and put it on the end */ + cop->b_wptr = wp; + olen = 256; + cop = allocb(olen, BPRI_MED); + if (cop == NULL) + goto nobuffs; + linkb(outgoing, cop); + wp = cop->b_wptr; + } + if (SPECIAL(p, c)) { + *wp++ = PPP_ESCAPE; + *wp++ = c ^ PPP_TRANS; + olen -= 2; + } else { + *wp++ = c; + --olen; + } + fcs = PPP_FCS(fcs, c); + } + mp = mp->b_cont; /* look at the next block */ + } /* end while(mp) */ + + /* + * Add the FCS and the trailing flag. + */ + if (olen < 5) { + /* grab another message block for FCS and trailing flag */ + cop->b_wptr = wp; + cop = allocb(5, BPRI_MED); + if (cop == NULL) + goto nobuffs; + linkb(outgoing, cop); + wp = cop->b_wptr; + } + fcs ^= 0xffff; /* XOR the resulting FCS */ + c = fcs & 0xff; + if (SPECIAL(p, c)) { + *wp++ = PPP_ESCAPE; + *wp++ = c ^ PPP_TRANS; + } else + *wp++ = c; + c = fcs >> 8; + if (SPECIAL(p, c)) { + *wp++ = PPP_ESCAPE; + *wp++ = c ^ PPP_TRANS; + } else + *wp++ = c; + *wp++ = PPP_FLAG; /* add trailing PPP_FLAG */ + + cop->b_wptr = wp; + freemsg(m0); + + /* + * now we check to see if the lower queue has entries, if so, + * we assume that we don't need a leading PPP_FLAG because + * these packets will be sent back to back. + */ + if (qsize(q->q_next) > 0) { + /* entries in next queue, remove the leading PPP_FLAG */ + ++outgoing->b_rptr; + } + +#if DEBUGS + if (p->pai_flags & PAI_FLAGS_LOG_OUTPKT) + ppp_dump_frame(p, outgoing, " sent output"); +#endif + putnext(q, outgoing); + continue; + + nobuffs: /* well, we ran out of memory somewhere */ + if (outgoing) + freemsg(outgoing); /* throw away what we have already */ + putbq(q, m0); /* put back the original message */ + putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR); + qenable(q); /* reschedule ourselves for later */ + return; + } /* end while(getq()) */ +} /* end function */ + +static int +ppp_async_rput(q, mp) + queue_t *q; + register mblk_t *mp; +{ + switch (mp->b_datap->db_type) { + + case M_FLUSH: + if(*mp->b_rptr & FLUSHR) + flushq(q, FLUSHDATA); + putnext(q, mp); /* send it along too */ + break; + + case M_DATA: + putq(q, mp); /* queue it for my service routine */ + break; + + default: + putnext(q,mp); /* don't know what to do with this, so send it along */ + } +} + +static u_long paritytab[8] = { + 0x96696996, 0x69969669, 0x69969669, 0x96696996, + 0x69969669, 0x96696996, 0x96696996, 0x69969669, +}; + +static int +ppp_async_rsrv(q) + queue_t *q; +{ + register mblk_t *mp, *bp; + register PAI *p; + register u_char *cp,c; + mblk_t *m0; + register u_char *wptr; + int bcount; + + p = (PAI *) q->q_ptr; + +#define INPUT_ERROR(q) putctl1(q, M_CTL, IF_INPUT_ERROR) +#define STUFF_CHAR(p,c) (*wptr++ = (c), (p)->pai_buffcount++) +#define FLUSHEM(q, p) (INPUT_ERROR(q), (p)->pai_flags |= PAI_FLAGS_FLUSH) + + while ((mp = getq(q)) != NULL) { + /* we can only get M_DATA types into our Queue, + due to our Put function */ + if (!canput(q->q_next)) { + putbq(q, mp); + return; + } + m0 = mp; /* remember first message block */ + for (; mp != NULL; mp = mp->b_cont) { /* for each message block */ + cp = mp->b_rptr; + while (cp < mp->b_wptr) { + c = *cp++; + + /* Accumulate info to help with detecting + non 8-bit clean links. */ + if (c & 0x80) + p->pai_flags |= PAI_FLAGS_B7_1; + else + p->pai_flags |= PAI_FLAGS_B7_0; + if (paritytab[c >> 5] & (1 << (c & 0x1F))) + p->pai_flags |= PAI_FLAGS_PAR_ODD; + else + p->pai_flags |= PAI_FLAGS_PAR_EVEN; + + /* Throw out chars in the receive asyncmap. */ + if (c < 0x20 && (p->pai_rasyncmap & (1 << c))) + continue; + + /* A flag marks the end of a frame. */ + if (c == PPP_FLAG) { + bp = p->pai_buffer; + bcount = p->pai_buffcount; + p->pai_buffer = NULL; + p->pai_buffcount = 0; + + /* if the escape indicator is set, then we have + seen the packet abort sequence "}~". */ + if (p->pai_flags & (PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH)) { + if ((p->pai_flags & PAI_FLAGS_FLUSH) == 0) + DLOG("ppp_async: packet abort\n", 0); + p->pai_flags &= ~(PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH); + if (bp) + freemsg(bp); + continue; + } + + if (bcount > PPP_FCSLEN) { /* discard FCS */ + adjmsg(bp, -PPP_FCSLEN); + bcount -= PPP_FCSLEN; + } + + if (bcount < PPP_HDRLEN) { + if (bcount) { + INPUT_ERROR(q); + DLOG("ppp_async: short input packet (%d)\n", + bcount); + } + if (bp) + freemsg(bp); + continue; + } + + if (bp) { + if (p->pai_fcs == PPP_GOODFCS) { +#if DEBUGS + if (p->pai_flags & PAI_FLAGS_LOG_INPKT) + ppp_dump_frame(p, bp, " got input"); +#endif /*DEBUGS*/ + putnext(q, bp); + } + else { + INPUT_ERROR(q); + freemsg(bp); + DLOG("ppp_async: FCS Error\n", 0); + } + } + continue; + } + + /* here c != PPP_FLAG */ + if (p->pai_flags & PAI_FLAGS_FLUSH) { + while (cp < mp->b_wptr && *cp != PPP_FLAG) + ++cp; + continue; + } + + if (p->pai_flags & PAI_FLAGS_ESCAPED) { + p->pai_flags &= ~PAI_FLAGS_ESCAPED; /* clear esc flag */ + c ^= PPP_TRANS; + } else if (c == PPP_ESCAPE) { + if (cp >= mp->b_wptr || (c = *cp) == PPP_FLAG + || c < 0x20 && (p->pai_rasyncmap & (1 << c))) { + p->pai_flags |= PAI_FLAGS_ESCAPED; + continue; + } + c ^= PPP_TRANS; + ++cp; + } + + /* here we check to see if we have a buffer. + If we don't, we assume that this is the first char + for the buffer, and we allocb one */ + + if (!p->pai_buffer) { + /* we allocate buffer chains in blocks of ALLOCBSIZE */ + + if (!(p->pai_buffer = allocb(ALLOCBSIZE, BPRI_MED))) { + FLUSHEM(q, p); + continue; + /* if we don't get a buffer, is there some way + to recover and requeue later? rather than flushing + the current packet... ? */ + } + p->pai_bufftail = p->pai_buffer; + } + wptr = p->pai_bufftail->b_wptr; + + if (!p->pai_buffcount) { + p->pai_fcs = PPP_INITFCS; + if (c != PPP_ALLSTATIONS) { + if (p->pai_flags & PAI_FLAGS_RCV_COMPAC) { + STUFF_CHAR(p, PPP_ALLSTATIONS); + STUFF_CHAR(p, PPP_UI); + } + else { + DLOG("ppp_async: missed ALLSTATIONS (0xff), got 0x%x\n", c); + FLUSHEM(q, p); + continue; + } + } + } /* end if !p->pai_buffcount */ + + if (p->pai_buffcount == 1 && c != PPP_UI) { + DLOG("ppp_async: missed UI (0x3), got 0x%x\n", c); + FLUSHEM(q,p); + continue; + } + + if (p->pai_buffcount == 2 && (c & 1) == 1) { + if (p->pai_flags & PAI_FLAGS_RCV_COMPPROT) + STUFF_CHAR(p, 0); + else { + DLOG("ppp_async: bad protocol high byte %x\n", c); + FLUSHEM(q, p); + continue; + } + } + + if (p->pai_buffcount == 3 && (c & 1) == 0) { + DLOG("ppp_async: bad protocol low byte %x\n", c); + FLUSHEM(q, p); + continue; + } + + if (p->pai_buffcount >= p->pai_buffsize) { /* overrun */ + DLOG("ppp_async: too many chars in input buffer %d\n", + p->pai_buffcount); + FLUSHEM(q, p); + continue; + } + + /* determine if we have enough space in the buffer */ + if (wptr >= p->pai_bufftail->b_datap->db_lim) { + p->pai_bufftail->b_wptr = wptr; + if (!(p->pai_bufftail = allocb(ALLOCBSIZE, BPRI_MED))) { + DLOG("ppp_async: couldn't get buffer for tail\n", 0); + FLUSHEM(q, p); /* discard all of it */ + continue; + } + linkb(p->pai_buffer, p->pai_bufftail); + wptr = p->pai_bufftail->b_wptr; + } + + STUFF_CHAR(p, c); + p->pai_fcs = PPP_FCS(p->pai_fcs, c); + while (cp < mp->b_wptr + && wptr < p->pai_bufftail->b_datap->db_lim + && (c = *cp) != PPP_FLAG && c != PPP_ESCAPE) { + if (c >= 0x20 || (p->pai_rasyncmap & (1 << c)) == 0) { + STUFF_CHAR(p, c); + p->pai_fcs = PPP_FCS(p->pai_fcs, c); + } + ++cp; + } + p->pai_bufftail->b_wptr = wptr; + + } /* end while cp < wptr */ + } /* end for each block */ + /* discard this message now */ + freemsg(m0); + } /* end while getq */ + +} + +#if DEBUGS +/* + * here is where we will dump out a frame in hex using the log() + * function if ppp_async_input_debug is non-zero. As this function is + * a pig, we only print up to the number of bytes specified by the value of + * the ppp_async_max_dump_bytes variable so as to not cause too many + * timeouts. + */ + +static void +ppp_dump_frame(p, mptr, msg) + register PAI *p; + register mblk_t *mptr; + char *msg; +{ + register u_char *rptr; + register u_int i, mlen, frame_length; + char buf[2*MAX_DUMP_BYTES+4]; /* tmp buffer */ + char *bp = buf; + static char digits[] = "0123456789abcdef"; + + frame_length = i = msgdsize(mptr); + bsdlog(LOG_INFO, "ppp_async%d:%s frame of %d bytes\n", p - pai, + msg, frame_length); + rptr = mptr->b_rptr; /* get pointer to beginning */ + mlen = mptr->b_wptr - rptr; /* get length of this dblock */ + + /* only dump up to MAX_DUMP_BYTES */ + if (i > ppp_async_max_dump_bytes) + i = ppp_async_max_dump_bytes; + + while (i--) { /* convert to ascii hex */ + while (mlen == 0) { /* get next dblock */ + mptr = mptr->b_cont; + if (mptr) { /* are we done? */ + rptr = mptr->b_rptr; /* nope, get next dblock */ + mlen = mptr->b_wptr - rptr; + } + else { /* no more dblocks */ + if (i != 0) + bsdlog(LOG_ERR, "ppp_async: ran out of data! (this shouldn't happen\n"); + break; + } + } + --mlen; + *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ + *bp++ = digits[*rptr++ & 0xf]; + } + + /* add a '>' to show that frame was truncated*/ + if (ppp_async_max_dump_bytes < frame_length) + *bp++ = '>'; + *bp = 0; + bsdlog(LOG_INFO,"ppp_async: %s\n", buf); +} +#endif /* DEBUGS */ + +#endif /* NUM_PPP > 0 */ diff --git a/aix4/ppp_comp.c b/aix4/ppp_comp.c new file mode 100644 index 0000000..58f26ad --- /dev/null +++ b/aix4/ppp_comp.c @@ -0,0 +1,437 @@ +/* + * ppp_comp.c - STREAMS module for kernel-level CCP support. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * + * $Id: ppp_comp.c,v 1.1 1994/12/05 00:29:21 paulus Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PACKETPTR mblk_t * +#include + +static int ppp_comp_open(), ppp_comp_close(); +static int ppp_comp_rput(), ppp_comp_wput(); +static void ppp_comp_ccp(); + +static struct module_info minfo = { + 0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096, +}; + +static struct qinit r_init = { + ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close, + NULL, &minfo, NULL +}; + +static struct qinit w_init = { + ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL +}; + +struct streamtab ppp_compinfo = { + &r_init, &w_init, NULL, NULL +}; + +struct ppp_comp_state { + int ccp_state; + int debug; + int mru; + struct compressor *xcomp; + void *xstate; + struct compressor *rcomp; + void *rstate; +}; + +/* Bits in ccp_state are as defined in ppp_str.h. */ +#define CCP_ERR (CCP_ERROR | CCP_FATALERROR) + +/* + * List of compressors we know about. + */ + +extern struct compressor ppp_bsd_compress; + +struct compressor *ppp_compressors[] = { + &ppp_bsd_compress, + NULL +}; + +strconf_t pppcompconf = { + "pppcomp", &ppp_compinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0 +}; + +int pppcomp_load(int cmd, struct uio *uiop) +{ + int rc = 0; + + switch (cmd) { + case CFG_INIT: + rc = str_install(STR_LOAD_MOD, &pppcompconf); + break; + case CFG_TERM: + rc = str_install(STR_UNLOAD_MOD, &pppcompconf); + break; + default: + rc = EINVAL; + break; + } + return(rc); +} + +static int +ppp_comp_open(q, dev, flag, sflag) + queue_t *q; + dev_t dev; + int flag; + int sflag; +{ + struct ppp_comp_state *cp; + + if (q->q_ptr == NULL) { + cp = (struct ppp_comp_state *) + xmalloc(sizeof(struct ppp_comp_state), 0, pinned_heap); + if (cp == NULL) { + return(ENOSR); + } + bzero(cp, sizeof(struct ppp_comp_state)); + OTHERQ(q)->q_ptr = q->q_ptr = (caddr_t) cp; + cp->ccp_state = 0; + cp->debug = 0; + cp->mru = PPP_MRU; + cp->xstate = NULL; + cp->rstate = NULL; + } + return 0; +} + +static int +ppp_comp_close(q) + queue_t *q; +{ + struct ppp_comp_state *cp; + + cp = (struct ppp_comp_state *) q->q_ptr; + if (cp != NULL) { + if (cp->xstate != NULL) + (*cp->xcomp->comp_free)(cp->xstate); + if (cp->rstate != NULL) + (*cp->rcomp->decomp_free)(cp->rstate); + xmfree(cp, pinned_heap); + q->q_ptr = NULL; + OTHERQ(q)->q_ptr = NULL; + } + return 0; +} + +static int +ppp_comp_wput(q, mp) + queue_t *q; + mblk_t *mp; +{ + struct iocblk *iop; + struct ppp_comp_state *cp; + mblk_t *cmp; + int error, len, proto, state; + struct ppp_option_data *odp; + struct compressor **comp; + + cp = (struct ppp_comp_state *) q->q_ptr; + switch (mp->b_datap->db_type) { + + case M_DATA: + /* first find out what the protocol is */ + if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN + || pullupmsg(mp, PPP_HDRLEN)) { + proto = PPP_PROTOCOL(mp->b_rptr); + if (proto == PPP_CCP) + ppp_comp_ccp(q, mp, 0); + else if (proto != PPP_LCP && (cp->ccp_state & CCP_COMP_RUN) + && cp->xstate != NULL) { + len = msgdsize(mp); + (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len, + (cp->ccp_state & CCP_ISUP? len: 0)); + /* XXX we really want the MTU here, not len */ + if (cmp != NULL) { + freemsg(mp); + mp = cmp; + } + } + } + putnext(q, mp); + break; + + case M_IOCTL: + iop = (struct iocblk *) mp->b_rptr; + error = -1; + switch ((unsigned int)iop->ioc_cmd) { + + case SIOCSIFCOMP: + /* set CCP state */ + if ((iop->ioc_count != sizeof(int)) && + (iop->ioc_count != TRANSPARENT)) { + error = EINVAL; + break; + } + state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN); + if ((state & CCP_ISOPEN) == 0) { + if (cp->xstate != NULL) { + (*cp->xcomp->comp_free)(cp->xstate); + cp->xstate = NULL; + } + if (cp->rstate != NULL) { + (*cp->rcomp->decomp_free)(cp->rstate); + cp->rstate = NULL; + } + cp->ccp_state = 0; + } else { + cp->ccp_state = (cp->ccp_state & ~CCP_ISUP) | state; + } + if (cp->debug) + bsdlog(LOG_INFO, "SIOCSIFCOMP %x, state = %x\n", + *(int *) mp->b_cont->b_rptr, cp->ccp_state); + error = 0; + iop->ioc_count = 0; + break; + + case SIOCGIFCOMP: + if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) { + error = ENOSR; + break; + } + *(int *)mp->b_cont->b_wptr = cp->ccp_state; + mp->b_cont->b_wptr += iop->ioc_count = sizeof(int); + break; + + case SIOCSCOMPRESS: + error = EINVAL; + if (iop->ioc_count != TRANSPARENT) + break; + odp = *((struct ppp_option_data **) mp->b_cont->b_rptr); + len = sizeof(odp->opt_data); + if (len > odp->length) + len = odp->length; + if (odp->opt_data[1] < 2 || odp->opt_data[1] > len) + break; + for (comp = ppp_compressors; *comp != NULL; ++comp) + if ((*comp)->compress_proto == odp->opt_data[0]) { + /* here's the handler! */ + error = 0; + if (odp->transmit) { + if (cp->xstate != NULL) + (*cp->xcomp->comp_free)(cp->xstate); + cp->xcomp = *comp; + cp->xstate = (*comp)->comp_alloc(odp->opt_data, len); + if (cp->xstate == NULL) + error = ENOSR; + } else { + if (cp->rstate != NULL) + (*cp->rcomp->decomp_free)(cp->rstate); + cp->rcomp = *comp; + cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len); + if (cp->rstate == NULL) + error = ENOSR; + } + if (cp->debug) + bsdlog(LOG_INFO, "SIOCSCOMPRESS %s len=%d\n", + odp->transmit? "xmit": "recv", len); + break; + } + iop->ioc_count = 0; + break; + + case SIOCSIFDEBUG: + /* set our debug flag from this */ + if ((iop->ioc_count == TRANSPARENT) || + (iop->ioc_count == sizeof(int))) { + cp->debug = *(int *) mp->b_cont->b_rptr & 1; + } + break; + + case SIOCSIFMRU: + /* remember this value */ + if ((iop->ioc_count == TRANSPARENT) || + (iop->ioc_count == sizeof(int))) { + cp->mru = *(int *) mp->b_cont->b_rptr; + } + break; + + } + + if (error < 0) + putnext(q, mp); + else if (error == 0) { + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); + } else { + mp->b_datap->db_type = M_IOCNAK; + iop->ioc_count = 0; + qreply(q, mp); + } + break; + + default: + putnext(q, mp); + } +} + +static int +ppp_comp_rput(q, mp) + queue_t *q; + mblk_t *mp; +{ + int proto, rv; + mblk_t *dmp; + struct ppp_comp_state *cp; + + cp = (struct ppp_comp_state *) q->q_ptr; + switch (mp->b_datap->db_type) { + + case M_DATA: + /* possibly a compressed packet to decompress, + or a CCP packet to take notice of. */ + if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN + || pullupmsg(mp, PPP_HDRLEN)) { + proto = PPP_PROTOCOL(mp->b_rptr); + if (proto == PPP_CCP) + ppp_comp_ccp(q, mp, 1); + else if (proto == PPP_COMP) { + if ((cp->ccp_state & CCP_ISUP) + && (cp->ccp_state & CCP_DECOMP_RUN) && cp->rstate + && (cp->ccp_state & CCP_ERR) == 0) { + rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp); + if (dmp != NULL) { + freemsg(mp); + mp = dmp; + } else { + switch (rv) { + case DECOMP_OK: + /* no error, but no packet returned */ + freemsg(mp); + mp = NULL; + break; + case DECOMP_ERROR: + cp->ccp_state |= CCP_ERROR; + break; + case DECOMP_FATALERROR: + cp->ccp_state |= CCP_FATALERROR; + break; + } + } + } + } else if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) { + (*cp->rcomp->incomp)(cp->rstate, mp); + } + } + if (mp != NULL) + putnext(q, mp); + break; + + default: + putnext(q, mp); + } +} + +static void +ppp_comp_ccp(q, mp, rcvd) + queue_t *q; + mblk_t *mp; + int rcvd; +{ + int len, clen; + struct ppp_comp_state *cp; + unsigned char *dp; + + len = msgdsize(mp); + if (len < PPP_HDRLEN + CCP_HDRLEN || !pullupmsg(mp, len)) + return; + cp = (struct ppp_comp_state *) q->q_ptr; + dp = mp->b_rptr + PPP_HDRLEN; + len -= PPP_HDRLEN; + clen = CCP_LENGTH(dp); + if (clen > len) + return; + if (cp->debug) + bsdlog(LOG_INFO, "CCP %s: code=%x len=%d\n", rcvd? "rcvd": "sent", + CCP_CODE(dp), clen); + + switch (CCP_CODE(dp)) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: + cp->ccp_state &= ~CCP_ISUP; + break; + + case CCP_CONFACK: + if ((cp->ccp_state & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN + && clen >= CCP_HDRLEN + CCP_OPT_MINLEN + && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) { + if (!rcvd) { + if (cp->xstate != NULL + && (*cp->xcomp->comp_init) + (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN, + 0, /* XXX: should be unit */ + cp->debug)) + cp->ccp_state |= CCP_COMP_RUN; + } else { + if (cp->rstate != NULL + && (*cp->rcomp->decomp_init) + (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN, + 0/* unit */, cp->mru, cp->debug)) + cp->ccp_state = (cp->ccp_state & ~CCP_ERR) + | CCP_DECOMP_RUN; + } + } + break; + + case CCP_RESETACK: + if (cp->ccp_state & CCP_ISUP) { + if (!rcvd) { + if (cp->xstate && (cp->ccp_state & CCP_COMP_RUN)) + (*cp->xcomp->comp_reset)(cp->xstate); + } else { + if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) { + (*cp->rcomp->decomp_reset)(cp->rstate); + cp->ccp_state &= ~CCP_ERROR; + } + } + } + break; + } + + if (cp->debug) + bsdlog(LOG_INFO, "ccp_state = %x\n", cp->ccp_state); +} diff --git a/aix4/ppp_if.c b/aix4/ppp_if.c new file mode 100644 index 0000000..87ecefa --- /dev/null +++ b/aix4/ppp_if.c @@ -0,0 +1,1123 @@ +/* + ppp_if.c - Streams PPP interface module + + top level module handles if_ and packetizing PPP packets. + + Copyright (C) 1990 Brad K. Clements, All Rights Reserved + See copyright notice in NOTES + +*/ + +#define VJC 1 +#include + +#ifndef PPP_VD +#include "ppp.h" +#endif + +#if NUM_PPP > 0 + +#define STREAMS 1 + +#define PPP_STATS 1 /* keep statistics */ +#define DEBUGS 1 + +#include +#include +#include +#include +#include + +#include +/* +#include +*/ +/* +#include +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define _NETINET_IN_SYSTM_H_ +typedef u_long n_long; +#include + +#include +#include + +#ifdef VJC +#undef SPECIAL_I +#include +#endif + +#ifdef PPP_STATS +#define INCR(comp) ++p->pii_stats.comp +#else +#define INCR(comp) +#endif + +#define MAX_PKTSIZE 4096 /* max packet size including framing */ +#define PPP_FRAMING 6 /* 4-byte header + 2-byte FCS */ +#define MAX_IPHDR 128 /* max TCP/IP header size */ +#define MAX_VJHDR 20 /* max VJ compressed header size (?) */ + +/* + * Network protocols we support. + */ +#define NP_IP 0 +#define NUM_NP 1 /* # protocols supported */ + +/* + * Structure used within the ppp_if streams module. + */ +struct ppp_if_info { + int pii_flags; + struct ifnet pii_ifnet; + queue_t *pii_writeq; /* used by ppp_output */ + enum NPmode pii_npmode[NUM_NP]; + mblk_t *pii_npq; /* list of packets queued up */ + mblk_t **pii_npq_tail; +#ifdef VJC + struct vjcompress pii_sc_comp; /* vjc control buffer */ +#endif +#ifdef PPP_STATS + struct pppstat pii_stats; +#endif +}; + +/* + * Values for pii_flags. + */ +#define PII_FLAGS_INUSE 0x1 /* in use by a stream */ +#define PII_FLAGS_ATTACHED 0x8 /* already if_attached */ +#define PII_FLAGS_VJC_ON 0x10 /* VJ TCP header compression enabled */ +#define PII_FLAGS_VJC_NOCCID 0x20 /* VJ: don't compress conn. id */ +#define PII_FLAGS_VJC_REJ 0x40 /* receive: reject VJ comp */ +#define PII_FLAGS_DEBUG 0x80 /* enable debug printout */ + +#ifdef DEBUGS +#include +#define DLOG(s,a) if (p->pii_flags&PII_FLAGS_DEBUG) bsdlog(LOG_INFO, s, a) +#else +#define DLOG(s) {} +#endif + +#ifdef PPP_SNIT +#include +#include +/* Use a fake link level header to make etherfind and tcpdump happy. */ +static struct ether_header header = {{1}, {2}, ETHERTYPE_IP}; +static struct nit_if nif = {(caddr_t)&header, sizeof(header), 0, 0}; +#endif + +static int ppp_if_open(), ppp_if_close(), ppp_if_rput(), ppp_if_wput(), + ppp_if_wsrv(), ppp_if_rsrv(); + +static struct module_info minfo ={ + 0xbad,"ppp_if",0, INFPSZ, 16384, 4096 +}; + +static struct qinit r_init = { + ppp_if_rput, ppp_if_rsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL +}; +static struct qinit w_init = { + ppp_if_wput, ppp_if_wsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL +}; +struct streamtab ppp_ifinfo = { + &r_init, &w_init, NULL, NULL +}; + +typedef struct ppp_if_info PII; + +PII *pii; + +int ppp_output(), ppp_ioctl(); +static void if_release_addrs(), if_delete_route(); + +strconf_t pppconf = { + "pppif", &ppp_ifinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0 +}; + +int ppp_load(int cmd, struct uio *uiop) +{ + int rc = 0; + + switch (cmd) { + case CFG_INIT: + rc = str_install(STR_LOAD_MOD, &pppconf); + break; + case CFG_TERM: + rc = str_install(STR_UNLOAD_MOD, &pppconf); + break; + default: + rc = EINVAL; + break; + } + if ((rc == 0) && !(pii = xmalloc(sizeof(PII) * NUM_PPP, 0, pinned_heap))) + rc = ENOMEM; + else + bzero(pii, sizeof(PII) * NUM_PPP); + + return(rc); +} + +int +ppp_attach(unit) + int unit; +{ + register struct ifnet *ifp = &pii[unit].pii_ifnet; + + ifp->if_name = "ppp"; + ifp->if_type = IFT_PTPSERIAL; + ifp->if_mtu = PPP_MTU; + ifp->if_flags = IFF_POINTOPOINT; + ifp->if_unit = unit; + ifp->if_ioctl = ppp_ioctl; + ifp->if_output = ppp_output; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + if_attach(ifp); + if_nostat(ifp); + pii[unit].pii_flags |= PII_FLAGS_ATTACHED; +} + + +int +ppp_unattach(unit) + int unit; +{ + struct ifnet *ifp = &pii[unit].pii_ifnet; + struct ifnet **p; + int s; + + if (!(pii[unit].pii_flags & PII_FLAGS_ATTACHED)) + return 0; + + /* remove interface from interface list */ + for (p = &ifp; *p; p = &((*p)->if_next)) { + if (*p == ifp) { + *p = (*p)->if_next; + + /* mark it down and flush it's que */ + if_down(ifp); + + /* free any addresses hanging off the intf */ + if_release_addrs(ifp); + + pii[unit].pii_flags &= ~PII_FLAGS_ATTACHED; + + return 0; + } + } + + return -1; +} + + +static void +if_release_addrs(ifp) +register struct ifnet *ifp; +{ + register struct in_ifaddr **addr; + register struct ifaddr *ifa, *ifanxt; + register int s; + + if_delete_route(ifp); + + for (addr = &in_ifaddr; *addr; ) { + if ((*addr)->ia_ifp == ifp) + *addr = (*addr)->ia_next; + else + addr = &((*addr)->ia_next); + } + + /* + * Free all mbufs holding down this interface's address(es). + */ + for (ifa = ifp->if_addrlist; ifa; ifa = ifanxt) { + ifanxt = ifa->ifa_next; + m_free(dtom(ifa)); + } + ifp->if_addrlist = 0; +} + +/* + * Delete routes to the specified interface. + * Hacked from rtrequest(). + */ +static void +if_delete_route(ifp) +struct ifnet *ifp; +{ + extern int rttrash; /* routes not in table but not freed */ + register struct mbuf **mprev, *m; + register struct rtentry *route; + register int i; + + /* search host rt tbl */ +/* + for (i = 0; i < RTHASHSIZ; i++) { + mprev = &rthost[i]; + while (m = *mprev) { + route = mtod(m, struct rtentry *); + if (route->rt_ifp == ifp) { + *mprev = m->m_next; + if (route->rt_refcnt > 0) { + route->rt_flags &= ~RTF_UP; + rttrash++; + m->m_next = 0; + } else { + m_free(m); + } + } else + mprev = &m->m_next; + } + } +*/ + + /* search net rt tbl */ +/* + for (i = 0; i < RTHASHSIZ; i++) { + mprev = &rtnet[i]; + while (m = *mprev) { + route = mtod(m, struct rtentry *); + if (route->rt_ifp == ifp) { + *mprev = m->m_next; + if (route->rt_refcnt > 0) { + route->rt_flags &= ~RTF_UP; + rttrash++; + m->m_next = 0; + } else { + m_free(m); + } + } else + mprev = &m->m_next; + } + } +*/ +} + +int +ppp_busy() +{ + int x; + + for (x = 0; x < NUM_PPP; x++) { + if (pii[x].pii_flags & PII_FLAGS_INUSE) + return 1; + } + return 0; +} + +static PII * +ppp_if_alloc() +{ + int s, x; + PII *p; + + for (x = 0; x < NUM_PPP; x++) + if (!(pii[x].pii_flags & PII_FLAGS_INUSE)) + break; + if (x == NUM_PPP) { /* all buffers in use */ + return NULL; + } + p = &pii[x]; + p->pii_flags |= PII_FLAGS_INUSE; + return p; +} + +static void +ppp_if_init(q, p) + queue_t *q; + PII *p; +{ + int s, n; + + +#ifdef VJC + vj_compress_init(&p->pii_sc_comp, -1); +#endif +#ifdef PPP_STATS + bzero(&p->pii_stats, sizeof(p->pii_stats)); +#endif + if (!(p->pii_flags & PII_FLAGS_ATTACHED)) + ppp_attach(p - pii); /* attach it */ + else + p->pii_ifnet.if_mtu = PPP_MTU; + p->pii_writeq = WR(q); + /* set write Q and read Q to point here */ + WR(q)->q_ptr = q->q_ptr = (caddr_t) p; + p->pii_ifnet.if_flags |= IFF_RUNNING; + p->pii_flags &= PII_FLAGS_INUSE | PII_FLAGS_ATTACHED | PII_FLAGS_DEBUG; + for (n = 0; n < NUM_NP; ++n) + p->pii_npmode[n] = NPMODE_ERROR; + p->pii_npmode[NP_IP] = NPMODE_PASS; /* for backwards compatibility */ + p->pii_npq = NULL; + p->pii_npq_tail = &p->pii_npq; + + DLOG("ppp_if%d: init\n", p - pii); +} + +static int +ppp_if_open(q, dev, flag, sflag) + queue_t *q; + dev_t dev; + int flag, sflag; + +{ + if (!suser()) { + return(EPERM); + } + + return (0); +} + +static int +ppp_if_close(q) + queue_t *q; /* queue info */ +{ + PII *p = (PII *) q->q_ptr; + int s, n; + mblk_t *mp, *mq; + + if (p != NULL) { + if_down(&p->pii_ifnet); + p->pii_ifnet.if_flags &= ~IFF_RUNNING; + p->pii_flags &= ~PII_FLAGS_INUSE; + q->q_ptr = NULL; + for (mp = p->pii_npq; mp != NULL; mp = mq) { + mq = mp->b_next; + freemsg(mp); + } + p->pii_npq = NULL; + p->pii_npq_tail = &p->pii_npq; + DLOG("ppp_if%d: closed\n", p - pii); + } + return(0); /* no work to be done */ +} + + +static int +ppp_if_wput(q, mp) + queue_t *q; + register mblk_t *mp; +{ + register struct iocblk *i; + register PII *p; + int bits, flags, error, unit, s; + queue_t *oq; + int npix; + struct npioctl *npi; + mblk_t *mq, **mqnext; + struct ppp_stats *psp; + + switch (mp->b_datap->db_type) { + + case M_FLUSH: + if (*mp->b_rptr & FLUSHW) + flushq(q, FLUSHDATA); + putnext(q, mp); /* send it along too */ + break; + + case M_DATA: + putq(q, mp); /* queue it for my service routine */ + break; + + case M_IOCTL: + i = (struct iocblk *) mp->b_rptr; + p = (PII *) q->q_ptr; + switch ((unsigned int)i->ioc_cmd) { + + case SIOCSIFVJCOMP: /* enable or disable VJ compression */ +#ifdef VJC + if (i->ioc_count == TRANSPARENT) { + bits = *(u_int *) mp->b_cont->b_rptr; + DLOG("ppp_if: SIFVJCOMP %d\n", bits); + if (bits & 1) + p->pii_flags |= PII_FLAGS_VJC_ON; + else + p->pii_flags &= ~PII_FLAGS_VJC_ON; + if (bits & 2) + p->pii_flags |= PII_FLAGS_VJC_NOCCID; + else + p->pii_flags &= ~PII_FLAGS_VJC_NOCCID; + if (bits & 4) + p->pii_flags |= PII_FLAGS_VJC_REJ; + else + p->pii_flags &= ~PII_FLAGS_VJC_REJ; + bits >>= 4; /* now max conn id. */ + if (bits) + vj_compress_init(&p->pii_sc_comp, bits); + mp->b_datap->db_type = M_IOCACK; + i->ioc_count = 0; + qreply(q, mp); + break; + } +#endif + putnext(q, mp); + break; + + case SIOCGETU: /* get unit number */ + /* + * Allocate a unit if we don't already have one. + */ + error = 0; + if (p == (PII *) 0) { + p = ppp_if_alloc(); + if (p == NULL) + error = ENOBUFS; + else + ppp_if_init(RD(q), p); + } + if (error == 0 + && (mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) + error = ENOSR; + if (error == 0) { + *(int *) mp->b_cont->b_wptr = p->pii_ifnet.if_unit; + mp->b_cont->b_wptr += i->ioc_count = sizeof(int); + mp->b_datap->db_type = M_IOCACK; + } else { + i->ioc_error = error; + i->ioc_count = 0; + mp->b_datap->db_type = M_IOCNAK; + } + qreply(q,mp); + break; + + case SIOCSETU: /* set unit number */ + if ((i->ioc_count == sizeof(int)) || + (i->ioc_count == TRANSPARENT)) { + unit = *(int *)mp->b_cont->b_rptr; + if (p != NULL || (unsigned) unit > NUM_PPP) { + mp->b_datap->db_type = M_IOCNAK; + i->ioc_error = EINVAL; + i->ioc_count = 0; + error = EINVAL; + } else { + p = &pii[unit]; + if (p->pii_flags & PII_FLAGS_INUSE) { + oq = p->pii_writeq; + oq->q_ptr = RD(oq)->q_ptr = NULL; + q->q_ptr = RD(q)->q_ptr = (caddr_t) p; + p->pii_writeq = q; + } else { + ppp_if_init(RD(q), p); + } + mp->b_datap->db_type = M_IOCACK; + } + qreply(q, mp); + break; + } + putnext(q, mp); + break; + + case SIOCSIFDEBUG : + /* catch it on the way past to set our debug flag as well */ + if (i->ioc_count == TRANSPARENT) { + flags = *(int *)mp->b_cont->b_rptr; + if (flags & 1) + p->pii_flags |= PII_FLAGS_DEBUG; + else + p->pii_flags &= ~PII_FLAGS_DEBUG; + } + putnext(q, mp); + break; + + case SIOCGETNPMODE: + case SIOCSETNPMODE: + if (i->ioc_count == TRANSPARENT && p != NULL) { + npi = *((struct npioctl **) mp->b_cont->b_rptr); + switch (npi->protocol) { + case PPP_IP: + npix = NP_IP; + break; + default: + npix = -1; + } + if (npix < 0) { + i->ioc_error = EAFNOSUPPORT; + i->ioc_count = 0; + mp->b_datap->db_type = M_IOCNAK; + qreply(q, mp); + break; + } + if (i->ioc_cmd == SIOCSETNPMODE) { + if (p->pii_npmode[npix] == NPMODE_QUEUE + && npi->mode != NPMODE_QUEUE) { + for (mqnext = &p->pii_npq; (mq = *mqnext) != NULL; ) { + if (PPP_PROTOCOL(mq->b_rptr) != npi->protocol){ + mqnext = &mq->b_next; + continue; + } + *mqnext = mq->b_next; + if (npi->mode == NPMODE_PASS) { + putq(q, mq); /* q it for service routine */ + } else { + freemsg(mq); + } + } + p->pii_npq_tail = mqnext; + } + p->pii_npmode[npix] = npi->mode; + i->ioc_count = 0; + } else + npi->mode = p->pii_npmode[npix]; + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); + break; + } + putnext(q, mp); + break; + + default: /* unknown IOCTL call */ + putnext(q, mp); /* pass it along */ + } + break; + + default: + putnext(q, mp); /* don't know what to do with this, so send it along*/ + } +} + +static int +ppp_if_wsrv(q) + queue_t *q; +{ + register mblk_t *mp; + register PII *p; + + p = (PII *) q->q_ptr; + + while ((mp = getq(q)) != NULL) { + /* + * we can only get M_DATA types into our Queue, + * due to our Put function + */ + if (!canput(q->q_next)) { + putbq(q, mp); + return; + } + + /* increment count of outgoing packets */ + if (p != NULL) + INCR(ppp_opackets); + + /* just pass it along, nothing to do in this direction */ + putnext(q, mp); + } /* end while */ +} + + +static int +ppp_if_rput(q, mp) + queue_t *q; + register mblk_t *mp; +{ + register u_char c; + register PII *p; + + switch (mp->b_datap->db_type) { + + case M_FLUSH: + if (*mp->b_rptr & FLUSHR) + flushq(q, FLUSHDATA); + putnext(q, mp); /* send it along too */ + break; + + case M_DATA: + putq(q, mp); /* queue it for my service routine */ + break; + + case M_CTL: + p = (PII *) q->q_ptr; + if (p != NULL) { + c = *(u_char *) mp->b_rptr; + switch (c) { + case IF_INPUT_ERROR : + p->pii_ifnet.if_ierrors++; + INCR(ppp_ierrors); + DLOG("ppp_if: input error inc to %d\n", + p->pii_ifnet.if_ierrors); + break; + case IF_OUTPUT_ERROR : + p->pii_ifnet.if_oerrors++; + INCR(ppp_oerrors); + DLOG("ppp_if: output error inc to %d\n", + p->pii_ifnet.if_oerrors); + break; + } + } + putnext(q, mp); /* send it up to pppd */ + break; + + default: + putnext(q, mp); /* send along other message types */ + } +} + +static int +ppp_if_rsrv(q) + queue_t *q; +{ + register mblk_t *mp,*m0; +#ifdef VJC + register mblk_t *mvjc; + unsigned char *cp, *iphdr; + u_int hlen; +#endif + register PII *p; + struct mbuf *mb1, *mb2, *mbtail; + struct ifnet *ifp; + int len, xlen, count, s, pklen; + u_char *rptr; + int address, control; + + p = (PII *) q->q_ptr; + + while ((mp = getq(q)) != NULL) { + /* + * we can only get M_DATA types into our Queue, + * due to our Put function + */ + + if (p == NULL) { + if (!canput(q->q_next)) { + putbq(q, mp); + return; + } + putnext(q, mp); + continue; + } + + len = msgdsize(mp); +#ifdef PPP_STATS + p->pii_stats.ppp_ibytes += len; +#endif + + /* make sure ppp_header is completely in first block */ + if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN + && !pullupmsg(mp, PPP_HDRLEN)) { + DLOG("pullupmsg failed!\n", 0); + freemsg(mp); + p->pii_ifnet.if_ierrors++; + continue; + } + m0 = mp; /* remember first message block */ + +#ifdef VJC + switch (PPP_PROTOCOL(mp->b_rptr)) { + case PPP_VJC_COMP : + if ((p->pii_flags & PII_FLAGS_VJC_REJ) + || p->pii_npmode[NP_IP] != NPMODE_PASS) { + DLOG("VJC rejected\n", 0); + freemsg(mp); + continue; + } + address = PPP_ADDRESS(mp->b_rptr); + control = PPP_CONTROL(mp->b_rptr); + mp->b_rptr += PPP_HDRLEN; + len -= PPP_HDRLEN; + + /* + * Make sure the VJ header is in one message block. + */ + xlen = MIN(len, MAX_VJHDR); + if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) { + DLOG("pullupmsg vjc %d failed\n", xlen); + freemsg(mp); + continue; + } + + /* + * Decompress it, then get a buffer and put the + * decompressed header in it. + */ + xlen = vj_uncompress_tcp(mp->b_rptr, mp->b_wptr - mp->b_rptr, + len, &p->pii_sc_comp, &iphdr, &hlen); + if (xlen < 0) { + DLOG("ppp: vj_uncompress failed on type Compressed\n", 0); + freemsg(mp); + continue; + } + if (!(mvjc = allocb(hlen + PPP_HDRLEN, BPRI_MED))) { + DLOG("allocb mvjc failed (%d)\n", hlen + PPP_HDRLEN); + freemsg(mp); + continue; + } + cp = mvjc->b_rptr; + cp[0] = address; + cp[1] = control; + cp[2] = 0; + cp[3] = PPP_IP; + bcopy(iphdr, cp + PPP_HDRLEN, hlen); + mvjc->b_wptr = cp + PPP_HDRLEN + hlen; + mvjc->b_cont = mp; + mp->b_rptr += xlen; + m0 = mp = mvjc; + len += PPP_HDRLEN + hlen; + break; + + case PPP_VJC_UNCOMP : + if ((p->pii_flags & PII_FLAGS_VJC_REJ) + || p->pii_npmode[NP_IP] != NPMODE_PASS) { + DLOG("VJU rejected\n", 0); + freemsg(mp); + continue; + } + + /* + * Make sure the IP header is in one message block. + */ + xlen = MIN(len, MAX_IPHDR + PPP_HDRLEN); + if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) { + DLOG("pullupmsg vju %d failed\n", xlen); + freemsg(mp); + continue; + } + + /* + * "Uncompress" it. Basically this just copies information + * into p->pii_sc_comp and restores the protocol field of + * the IP header. + */ + if (!vj_uncompress_uncomp(mp->b_rptr + PPP_HDRLEN, + &p->pii_sc_comp)) { + DLOG("ppp: vj_uncompress failed on type Uncompresed\n", 0); + freemsg(mp); + continue; + } + mp->b_rptr[3] = PPP_IP; + break; + } +#endif + + switch (PPP_PROTOCOL(mp->b_rptr)) { + default: + if (!canput(q->q_next)) { + putbq(q, mp); + return; + } + INCR(ppp_ipackets); + p->pii_ifnet.if_ipackets++; + putnext(q, mp); + continue; + + case PPP_IP: + /* + * Don't let packets through until IPCP is up. + */ + INCR(ppp_ipackets); + p->pii_ifnet.if_ipackets++; + + if (!(p->pii_ifnet.if_flags & IFF_UP) + || p->pii_npmode[NP_IP] != NPMODE_PASS) { + DLOG("pkt ignored - IP down\n", 0); + freemsg(mp); + continue; + } + + /* + * Get the first mbuf and put the struct ifnet * in. + */ + MGETHDR(mb1, M_DONTWAIT, MT_DATA); + mb1->m_len = 0; + if (mb1 == NULL) { + p->pii_ifnet.if_ierrors++; + freemsg(m0); + continue; + } + len = MHLEN; + mbtail = mb2 = mb1; + pklen = 0; + + rptr = mp->b_rptr + PPP_HDRLEN; + xlen = mp->b_wptr - rptr; + for(;;) { + if (xlen == 0) { /* move to the next mblk */ + mp = mp->b_cont; + if (mp == NULL) + break; + xlen = mp->b_wptr - (rptr = mp->b_rptr); + continue; + } + if (len == 0) { + MGET(mb2, M_DONTWAIT, MT_DATA); + if (!mb2) { + /* if we couldn't get a buffer, drop the packet */ + p->pii_ifnet.if_ierrors++; + m_freem(mb1); /* discard what we've used already */ + mb1 = NULL; + break; + } + len = MLEN; + mb2->m_len = 0; + mbtail->m_next = mb2; + mbtail = mb2; + } + count = MIN(xlen, len); + bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count); + rptr += count; + len -= count; + xlen -= count; + pklen += count; + mb2->m_len += count; + } + + freemsg(m0); + if (mb1 == NULL) + continue; + +#ifdef PPP_SNIT + if (p->pii_ifnet.if_flags & IFF_PROMISC) { + struct mbuf *m = mb1; + + len = 0; + do { + len += m->m_len; + } while (m = m->m_next); + nif.nif_bodylen = len - sizeof(struct ifnet *); + mb1->m_off += sizeof(struct ifnet *); + snit_intr(&p->pii_ifnet, mb1, &nif); + mb1->m_off -= sizeof(struct ifnet *); + } +#endif +/* + if (IF_QFULL(&ipintrq)) { + IF_DROP(&ipintrq); + p->pii_ifnet.if_ierrors++; + m_freem(mb1); + } + else { +*/ + ifp = &p->pii_ifnet; + mb1->m_pkthdr.len = pklen; + mb1->m_pkthdr.rcvif = ifp; + find_input_type(0x0800, mb1, ifp, 0); + } + } /* end while */ +} + +/* ifp output procedure */ +int +ppp_output(ifp, m0, dst) + struct ifnet *ifp; + struct mbuf *m0; + struct sockaddr *dst; +{ + register PII *p = &pii[ifp->if_unit]; + struct mbuf *m1; + int error, s, len; + u_short protocol; +#ifdef VJC + int type; + u_char *vjhdr; +#endif + mblk_t *mp; + enum NPmode npmode; + + error = 0; + if (!(ifp->if_flags & IFF_UP)) { + error = ENETDOWN; + goto getout; + } + + switch (dst->sa_family) { +#ifdef INET + case AF_INET: +#ifdef PPP_SNIT + if (ifp->if_flags & IFF_PROMISC) { + struct mbuf *m = m0; + + len = 0; + do { + len += m->m_len; + } while (m = m->m_next); + nif.nif_bodylen = len; + snit_intr(ifp, m0, &nif); + } +#endif + protocol = PPP_IP; + npmode = p->pii_npmode[NP_IP]; + break; +#endif + + default: + DLOG("ppp: af%d not supported\n", dst->sa_family); + error = EAFNOSUPPORT; + goto getout; + } + + if (!p->pii_writeq) { + DLOG("ppp_if%d: no queue\n", p - pii); + error = EHOSTUNREACH; + goto getout; + } + + switch (npmode) { + case NPMODE_DROP: + goto getout; + case NPMODE_ERROR: + error = ENETDOWN; + goto getout; + } + +#ifdef VJC + if ((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) { + register struct ip *ip; + ip = mtod(m0, struct ip *); + if (ip->ip_p == IPPROTO_TCP) { + type = vj_compress_tcp(ip, m0->m_len, &p->pii_sc_comp, + !(p->pii_flags & PII_FLAGS_VJC_NOCCID), + &vjhdr); + switch (type) { + case TYPE_UNCOMPRESSED_TCP : + protocol = PPP_VJC_UNCOMP; + break; + case TYPE_COMPRESSED_TCP : + protocol = PPP_VJC_COMP; + len = vjhdr - (u_char *) ip; + m0->m_data += len; + m0->m_len -= len; + break; + } + } + } +#endif + + len = PPP_HDRLEN; + for (m1 = m0; m1; m1 = m1->m_next) + len += m1->m_len; + + if (!(mp = allocb(len, BPRI_MED))) { + DLOG("ppp_if%d: allocb failed\n", p - pii); + error = ENOBUFS; + goto getout; + } + +#ifdef PPP_STATS + p->pii_stats.ppp_obytes += len; +#endif + + *mp->b_wptr++ = PPP_ALLSTATIONS; + *mp->b_wptr++ = PPP_UI; + *mp->b_wptr++ = 0; + *mp->b_wptr++ = protocol; + for (m1 = m0; m1; m1 = m1->m_next) { /* copy all data */ + bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len); + mp->b_wptr += m1->m_len; + } + + p->pii_ifnet.if_opackets++; +DLOG("ppp_output npmode is %d\n",npmode); + if (npmode == NPMODE_PASS) { + putq(p->pii_writeq, mp); + } else { + mp->b_next = NULL; + *p->pii_npq_tail = mp; + p->pii_npq_tail = ∓ + } + + getout: + m_freem(m0); + if (error) { + INCR(ppp_oerrors); + p->pii_ifnet.if_oerrors++; + } + return (error); +} + +/* + * if_ ioctl requests +*/ +ppp_ioctl(ifp, cmd, data) + register struct ifnet *ifp; + unsigned int cmd; + caddr_t data; +{ + register struct ifaddr *ifa = (struct ifaddr *) data; + register struct ifreq *ifr = (struct ifreq *) data; + struct ppp_stats *psp; + struct ppp_comp_stats *pcp; + PII *p; + int error = 0; + + switch (cmd) { + case SIOCSIFFLAGS : + /* This happens every time IFF_PROMISC has been changed. */ + if (!ifr) + break; + if (!suser()) { + error = EPERM; + break; + } + + /* clear the flags that can be cleared */ + ifp->if_flags &= (IFF_CANTCHANGE); + /* or in the flags that can be changed */ + ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE); + break; + + case SIOCGIFFLAGS : + ifr->ifr_flags = ifp->if_flags; + break; + + case SIOCSIFADDR : + if( ifa->ifa_addr->sa_family != AF_INET) + error = EAFNOSUPPORT; + break; + + case SIOCSIFDSTADDR : + if (ifa->ifa_addr->sa_family != AF_INET) + error = EAFNOSUPPORT; + break; + + case SIOCSIFMTU : + if (!suser()) { + error = EPERM; + break; + } + if (ifr->ifr_mtu > MAX_PKTSIZE - PPP_FRAMING) { + error = EINVAL; + break; + } + ifp->if_mtu = ifr->ifr_mtu; + break; + + case SIOCGIFMTU : + ifr->ifr_mtu = ifp->if_mtu; + break; + + case SIOCGPPPSTATS: + p = &pii[ifp->if_unit]; + psp = (struct ppp_stats *) &((struct ifpppstatsreq *)data)->stats; + bzero(psp, sizeof(struct ppp_stats)); +#ifdef PPP_STATS + psp->p = p->pii_stats; +#endif +#if defined(VJC) && !defined(VJ_NO_STATS) + psp->vj = p->pii_sc_comp.stats; +#endif + break; + + case SIOCGPPPCSTATS: + p = &pii[ifp->if_unit]; + pcp = (struct ppp_comp_stats *)&((struct ifpppcstatsreq *)data)->stats; + bzero(pcp, sizeof(struct ppp_comp_stats)); + /* XXX we need to fill in the compression stats */ + break; + + default : + error = EINVAL; + break; + } + return(error); +} + +#endif -- 2.39.2