* 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
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
*
- * $Id: ppp.c,v 1.2 1995/12/18 03:57:27 paulus Exp $
+ * $Id: ppp.c,v 1.9 1997/03/04 03:31:35 paulus Exp $
*/
/*
- * This file is used under Solaris 2, SVR4, and SunOS 4.
+ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
*/
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/errno.h>
+#ifdef __osf__
+#include <sys/ioctl.h>
+#include <sys/cmn_err.h>
+#define queclass(mp) ((mp)->b_band & QPCTL)
+#else
#include <sys/ioccom.h>
+#endif
#include <sys/time.h>
#ifdef SVR4
#include <sys/cmn_err.h>
#include <net/pppio.h>
#include "ppp_mod.h"
+/*
+ * Modifications marked with #ifdef PRIOQ are for priority queueing of
+ * interactive traffic, and are due to Marko Zec <zec@japa.tel.fer.hr>.
+ */
+#ifdef PRIOQ
+#include <netinet/in.h>
+#endif /* PRIOQ */
+
#ifdef __STDC__
#define __P(x) x
#else
struct upperstr *ppa; /* control stream for our ppa */
struct upperstr *next; /* next stream for this ppa */
uint ioc_id; /* last ioctl ID for this stream */
+ enum NPmode npmode; /* what to do with packets on this SAP */
/*
* There is exactly one control stream for each PPA.
* The following fields are only used for control streams.
#define US_LASTMOD 8 /* no PPP modules below us */
#define US_DBGLOG 0x10 /* log various occurrences */
+
+#ifdef PRIOQ
+static u_char max_band=0;
+static u_char def_band=0;
+
+#define IPPORT_DEFAULT 65535
+
+/*
+ * Port priority table
+ * Highest priority ports are listed first, lowest are listed last.
+ * ICMP & packets using unlisted ports will be treated as "default".
+ * If IPPORT_DEFAULT is not listed here, "default" packets will be
+ * assigned lowest priority.
+ * Each line should be terminated with "0".
+ * Line containing only "0" marks the end of the list.
+ */
+
+static u_short prioq_table[]= {
+ 113, 53, 0,
+ 22, 23, 513, 517, 518, 0,
+ 514, 21, 79, 111, 0,
+ 25, 109, 110, 0,
+ IPPORT_DEFAULT, 0,
+ 20, 70, 80, 8001, 8008, 8080, 0, /* 8001,8008,8080 - common proxy ports */
+0 };
+
+#endif /* PRIOQ */
+
+
static upperstr_t *minor_devs = NULL;
static upperstr_t *ppas = NULL;
static upperstr_t *find_dest __P((upperstr_t *, int));
static int putctl2 __P((queue_t *, int, int, int));
static int putctl4 __P((queue_t *, int, int, int));
+static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+#define PPP_ID 0xb1a6
static struct module_info ppp_info = {
- 0xb1a6, "ppp", 0, 512, 512, 128
+#ifdef PRIOQ
+ PPP_ID, "ppp", 0, 512, 512, 384
+#else
+ PPP_ID, "ppp", 0, 512, 512, 128
+#endif /* PRIOQ */
};
static struct qinit pppurint = {
upperstr_t *up;
upperstr_t **prevp;
minor_t mn;
+#ifdef PRIOQ
+ u_short *ptr;
+ u_char new_band;
+#endif /* PRIOQ */
if (q->q_ptr)
DRV_OPEN_OK(dev); /* device is already open */
+#ifdef PRIOQ
+ /* Calculate max_bband & def_band from definitions in prioq.h
+ This colud be done at some more approtiate time (less often)
+ but this way it works well so I'll just leave it here */
+
+ max_band = 1;
+ def_band = 0;
+ ptr = prioq_table;
+ while (*ptr) {
+ new_band = 1;
+ while (*ptr)
+ if (*ptr++ == IPPORT_DEFAULT) {
+ new_band = 0;
+ def_band = max_band;
+ }
+ max_band += new_band;
+ ptr++;
+ }
+ if (def_band)
+ def_band = max_band - def_band;
+ --max_band;
+#endif /* PRIOQ */
+
if (sflag == CLONEOPEN) {
mn = 0;
for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
#endif
up->sap = -1;
up->last_sent = up->last_recv = time;
+ up->npmode = NPMODE_DROP;
q->q_ptr = (caddr_t) up;
WR(q)->q_ptr = (caddr_t) up;
noenable(WR(q));
break;
}
}
- kmem_free(up, sizeof(upperstr_t));
+ FREE(up, sizeof(upperstr_t));
--ppp_count;
return 0;
queue_t *q;
mblk_t *mp;
{
- upperstr_t *us, *usnext, *ppa, *os;
+ upperstr_t *us, *usnext, *ppa, *os, *nps;
struct iocblk *iop;
struct linkblk *lb;
#ifdef LACHTCP
int i;
#endif
queue_t *lq;
- int error, n;
+ int error, n, sap;
mblk_t *mq;
struct ppp_idle *pip;
+ int len;
+#ifdef PRIOQ
+ queue_t *tlq;
+#endif /* PRIOQ */
us = (upperstr_t *) q->q_ptr;
switch (mp->b_datap->db_type) {
break;
}
#ifdef NO_DLPI
- if ((us->flags & US_CONTROL) == 0)
- us->ppa->last_sent = time;
+ if (!pass_packet(us->ppa, mp, 1)) {
+ freemsg(mp);
+ break;
+ }
#endif
if (!send_data(mp, us))
putq(q, mp);
putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id);
putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu);
+#ifdef PRIOQ
+ /* Lower tty driver's queue hiwat/lowat from default 4096/128
+ to 256/128 since we don't want queueing of data on
+ output to physical device */
+
+ freezestr(lq);
+ for (tlq = lq; tlq->q_next != NULL; tlq = tlq->q_next)
+ ;
+ strqset(tlq, QHIWAT, 0, 256);
+ strqset(tlq, QLOWAT, 0, 128);
+ unfreezestr(lq);
+#endif /* PRIOQ */
break;
case I_UNLINK:
}
break;
+ case PPPIO_NPMODE:
+ if (iop->ioc_count != 2 * sizeof(int))
+ break;
+ if ((us->flags & US_CONTROL) == 0)
+ break;
+ sap = ((int *)mp->b_cont->b_rptr)[0];
+ for (nps = us->next; nps != 0; nps = nps->next)
+ if (nps->sap == sap)
+ break;
+ if (nps == 0) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap);
+ break;
+ }
+ nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1];
+ if (nps->npmode == NPMODE_DROP || nps->npmode == NPMODE_ERROR)
+ flushq(WR(nps->q), FLUSHDATA);
+ else if (nps->npmode == NPMODE_PASS && qsize(WR(nps->q)) > 0
+ && (nps->flags & US_BLOCKED) == 0)
+ qenable(WR(nps->q));
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
case PPPIO_GIDLE:
if ((ppa = us->ppa) == 0)
break;
#ifdef LACHTCP
case SIOCSIFNAME:
- printf("SIOCSIFNAME\n");
/* Sent from IP down to us. Attach the ifstats structure. */
if (iop->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
break;
break;
case SIOCGIFFLAGS:
- printf("SIOCGIFFLAGS\n");
if (!(us->flags & US_CONTROL)) {
if (us->ppa)
us = us->ppa;
break;
case SIOCSIFFLAGS:
- printf("SIOCSIFFLAGS\n");
if (!(us->flags & US_CONTROL)) {
if (us->ppa)
us = us->ppa;
break;
case SIOCSIFADDR:
- printf("SIOCSIFADDR\n");
if (!(us->flags & US_CONTROL)) {
if (us->ppa)
us = us->ppa;
dl_bind_ack_t *ackp;
if (us->flags & US_DBGLOG)
- cmn_err(CE_CONT, "ppp/%d: dlpi prim %x len=%d\n", us->mn,
+ DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn,
d->dl_primitive, size);
switch (d->dl_primitive) {
case DL_INFO_REQ:
except that we accept ETHERTYPE_IP in place of PPP_IP. */
sap = d->bind_req.dl_sap;
us->req_sap = sap;
- DPRINT1("ppp bind %x\n", sap);
if (sap == ETHERTYPE_IP)
sap = PPP_IP;
if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) {
}
us->sap = -1;
us->state = DL_UNBOUND;
-#ifndef sun
+#ifdef LACHTCP
us->ppa->ifstats.ifs_active = 0;
#endif
dlpi_ok(q, DL_UNBIND_REQ);
DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu);
break;
}
- ppa->last_sent = time;
+ mp->b_band = 0;
+#ifdef PRIOQ
+ /* Extract s_port & d_port from IP-packet, the code is a bit
+ dirty here, but so am I, too... */
+ if (mp->b_datap->db_type == M_PROTO && us->sap == PPP_IP
+ && mp->b_cont != 0) {
+ u_char *bb, *tlh;
+ int iphlen, len;
+ u_short *ptr;
+ u_char band_unset, cur_band, syn;
+ u_short s_port, d_port;
+
+ bb = mp->b_cont->b_rptr; /* bb points to IP-header*/
+ len = mp->b_cont->b_wptr - mp->b_cont->b_rptr;
+ syn = 0;
+ s_port = IPPORT_DEFAULT;
+ d_port = IPPORT_DEFAULT;
+ if (len >= 20) { /* 20 = minimum length of IP header */
+ iphlen = (bb[0] & 0x0f) * 4;
+ tlh = bb + iphlen;
+ len -= iphlen;
+ switch (bb[9]) {
+ case IPPROTO_TCP:
+ if (len >= 20) { /* min length of TCP header */
+ s_port = (tlh[0] << 8) + tlh[1];
+ d_port = (tlh[2] << 8) + tlh[3];
+ syn = tlh[13] & 0x02;
+ }
+ break;
+ case IPPROTO_UDP:
+ if (len >= 8) { /* min length of UDP header */
+ s_port = (tlh[0] << 8) + tlh[1];
+ d_port = (tlh[2] << 8) + tlh[3];
+ }
+ break;
+ }
+ }
+
+ /*
+ * Now calculate b_band for this packet from the
+ * port-priority table.
+ */
+ ptr = prioq_table;
+ cur_band = max_band;
+ band_unset = 1;
+ while (*ptr) {
+ while (*ptr && band_unset)
+ if (s_port == *ptr || d_port == *ptr++) {
+ mp->b_band = cur_band;
+ band_unset = 0;
+ break;
+ }
+ ptr++;
+ cur_band--;
+ }
+ if (band_unset)
+ mp->b_band = def_band;
+ /* It may be usable to urge SYN packets a bit */
+ if (syn)
+ mp->b_band++;
+ }
+#endif /* PRIOQ */
/* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
if (mp->b_datap->db_ref > 1) {
np = allocb(PPP_HDRLEN, BPRI_HI);
mp->b_rptr[1] = PPP_UI;
mp->b_rptr[2] = us->sap >> 8;
mp->b_rptr[3] = us->sap;
- if (!send_data(mp, us))
- putq(q, mp);
+ if (!pass_packet(ppa, mp, 1)) {
+ freemsg(mp);
+ } else {
+ if (!send_data(mp, us))
+ putq(q, mp);
+ }
return;
#if DL_CURRENT_VERSION >= 2
}
#endif /* NO_DLPI */
+static int
+pass_packet(ppa, mp, outbound)
+ upperstr_t *ppa;
+ mblk_t *mp;
+ int outbound;
+{
+ /*
+ * Here is where we might, in future, decide whether to pass
+ * or drop the packet, and whether it counts as link activity.
+ */
+ if (outbound)
+ ppa->last_sent = time;
+ else
+ ppa->last_recv = time;
+ return 1;
+}
+
static int
send_data(mp, us)
mblk_t *mp;
queue_t *q;
upperstr_t *ppa;
- if (us->flags & US_BLOCKED)
+ if ((us->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE)
return 0;
ppa = us->ppa;
- if (ppa == 0) {
+ if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode);
freemsg(mp);
return 1;
}
if ((q = ppa->lowerq) == 0) {
/* try to send it up the control stream */
- if (canputnext(ppa->q)) {
- putnext(ppa->q, mp);
+ if (bcanputnext(ppa->q, mp->b_band)) {
+ /*
+ * The message seems to get corrupted for some reason if
+ * we just send the message up as it is, so we send a copy.
+ */
+ mblk_t *np = copymsg(mp);
+ freemsg(mp);
+ if (np != 0)
+ putnext(ppa->q, np);
return 1;
}
} else {
- if (canputnext(ppa->lowerq)) {
+ if (bcanputnext(ppa->lowerq, mp->b_band)) {
/*
* The lower write queue's put procedure just updates counters
* and does a putnext. We call it so that on SMP systems, we
us->nextppa = *usp;
*usp = us;
us->flags |= US_CONTROL;
+ us->npmode = NPMODE_PASS;
us->mtu = PPP_MRU;
us->mru = PPP_MRU;
putnext(us->q, mp);
break;
+ case M_HANGUP:
+ /*
+ * The serial device has hung up. We don't want to send
+ * the M_HANGUP message up to pppd because that will stop
+ * us from using the control stream any more. Instead we
+ * send a zero-length message as an end-of-file indication.
+ */
+ freemsg(mp);
+ mp = allocb(1, BPRI_HI);
+ if (mp == 0) {
+ DPRINT1("ppp/%d: couldn't allocate eof message!\n", ppa->mn);
+ break;
+ }
+ putnext(ppa->q, mp);
+ break;
+
default:
if (mp->b_datap->db_type == M_DATA) {
len = msgdsize(mp);
#ifdef INCR_IPACKETS
INCR_IPACKETS(ppa);
#endif
+ if (!pass_packet(ppa, mp, 0)) {
+ freemsg(mp);
+ break;
+ }
proto = PPP_PROTOCOL(mp->b_rptr);
if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
/*
putq(us->q, mp);
else
putq(q, mp);
- ppa->last_recv = time;
break;
}
}