* 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.1 1995/12/11 05:06:40 paulus Exp $
+ * $Id: ppp.c,v 1.4 1996/04/04 02:45:29 paulus Exp $
*/
/*
- * This file is used under Solaris 2 and SunOS 4.
+ * This file is used under Solaris 2, SVR4, and SunOS 4.
*/
#include <sys/types.h>
#include <sys/stropts.h>
#include <sys/errno.h>
#include <sys/ioccom.h>
+#include <sys/time.h>
#ifdef SVR4
#include <sys/cmn_err.h>
#include <sys/conf.h>
#endif /* SVR4 */
#include <net/ppp_defs.h>
#include <net/pppio.h>
+#include <net/bpf.h>
#include "ppp_mod.h"
#ifdef __STDC__
#endif
/*
- * The IP module uses this SAP value for IP packets.
+ * The IP module may use this SAP value for IP packets.
*/
#ifndef ETHERTYPE_IP
#define ETHERTYPE_IP 0x800
#define PPP_MAXMTU 65535
#endif
+extern time_t time;
+
/*
* Private information; one per upper stream.
*/
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.
int mru;
int mtu;
struct pppstat stats; /* statistics */
+ time_t last_sent; /* time last NP packet sent */
+ time_t last_recv; /* time last NP packet rcvd */
+ struct bpf_program active_f;/* filter for active packets */
+ struct bpf_program pass_f; /* filter for packets to pass */
#ifdef SOL2
kstat_t *kstats; /* stats for netstat */
#endif /* SOL2 */
up->ifflags = IFF_UP | IFF_POINTOPOINT;
#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));
kstat_delete(up->kstats);
#endif
+ if (up->active_f.bf_insns) {
+ kmem_free(up->active_f.bf_insns, up->active_f.bf_len);
+ up->active_f.bf_insns = 0;
+ }
+ if (up->pass_f.bf_insns) {
+ kmem_free(up->pass_f.bf_insns, up->pass_f.bf_len);
+ up->pass_f.bf_insns = 0;
+ }
+
q->q_ptr = NULL;
WR(q)->q_ptr = NULL;
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;
+ struct bpf_insn *ip;
+ struct bpf_program *dest;
us = (upperstr_t *) q->q_ptr;
switch (mp->b_datap->db_type) {
freemsg(mp);
break;
}
+#ifdef NO_DLPI
+ if (!pass_packet(us->ppa, mp, 1)) {
+ freemsg(mp);
+ break;
+ }
+#endif
if (!send_data(mp, us))
putq(q, mp);
break;
}
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)
+ 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;
+ mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
+ if (mq == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = mq;
+ mq->b_cont = 0;
+ pip = (struct ppp_idle *) mq->b_wptr;
+ pip->xmit_idle = time - ppa->last_sent;
+ pip->recv_idle = time - ppa->last_recv;
+ mq->b_wptr += sizeof(struct ppp_idle);
+ iop->ioc_count = sizeof(struct ppp_idle);
+ error = 0;
+ break;
+
+ case PPPIO_PASSFILT:
+ case PPPIO_ACTIVEFILT:
+ if ((us->flags & US_CONTROL) == 0)
+ break;
+ len = iop->ioc_count;
+ if (len > BPF_MAXINSNS * sizeof(struct bpf_insn)
+ || len % sizeof(struct bpf_insn) != 0)
+ break;
+ if (len > 0) {
+ if (!bpf_validate((struct bpf_insn *) mp->b_cont->b_rptr,
+ len / sizeof(struct bpf_insn)))
+ break;
+ ip = (struct bpf_insn *) ALLOC_NOSLEEP(len);
+ if (ip == 0) {
+ error = ENOSR;
+ break;
+ }
+ bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)ip, len);
+ } else
+ ip = 0;
+ dest = iop->ioc_cmd == PPPIO_ACTIVEFILT?
+ &us->active_f: &us->pass_f;
+ if (dest->bf_insns != 0)
+ kmem_free((caddr_t) dest->bf_insns, dest->bf_len);
+ dest->bf_len = len;
+ dest->bf_insns = ip;
+ break;
+
#ifdef LACHTCP
case SIOCSIFNAME:
printf("SIOCSIFNAME\n");
except that we accept ETHERTYPE_IP in place of PPP_IP. */
sap = d->bind_req.dl_sap;
us->req_sap = sap;
-#if DEBUG
- cmn_err(CE_CONT, "ppp bind %x\n", sap);
-#endif
+ 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);
dlpi_error(q, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
break;
}
- if (us->ppa == 0) {
+ if ((ppa = us->ppa) == 0) {
cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n");
break;
}
len = mp->b_cont == 0? 0: msgdsize(mp->b_cont);
- if (len > us->ppa->mtu) {
-#if DEBUG
- cmn_err(CE_CONT, "dlpi data too large (%d > %d)\n", len, us->mtu);
-#endif
+ if (len > ppa->mtu) {
+ DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu);
break;
}
/* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
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;
+{
+ int len, adr, pass;
+
+ if (PPP_PROTOCOL(mp->b_rptr) >= 0x8000
+ || (ppa->pass_f.bf_insns == 0 && ppa->active_f.bf_insns == 0))
+ return 1;
+ len = msgdsize(mp);
+ adr = *mp->b_rptr;
+ *mp->b_rptr = outbound;
+ pass = ppa->pass_f.bf_insns == 0
+ || bpf_filter(ppa->pass_f.bf_insns, mp, len, 0);
+ if (pass && (ppa->active_f.bf_insns == 0
+ || bpf_filter(ppa->active_f.bf_insns, mp, len, 0))) {
+ if (outbound)
+ ppa->last_sent = time;
+ else
+ ppa->last_recv = time;
+ }
+ *mp->b_rptr = adr;
+ return pass;
+}
+
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) {
freemsg(mp);
return 1;
}
us->nextppa = *usp;
*usp = us;
us->flags |= US_CONTROL;
+ us->npmode = NPMODE_PASS;
us->mtu = PPP_MRU;
us->mru = PPP_MRU;
#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) {
/*