* Paul Mackerras (paulus@cs.anu.edu.au).
*/
-/* $Id: if_ppp.c,v 1.7 1996/07/01 01:00:27 paulus Exp $ */
+/* $Id: if_ppp.c,v 1.12 1997/04/30 05:42:07 paulus Exp $ */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#endif
#if INET
#include <netinet/in.h>
#include <net/if_pppvar.h>
#include <machine/cpu.h>
+#define splsoftnet splnet
+
#ifndef NETISR_PPP
/* This definition should be moved to net/netisr.h */
#define NETISR_PPP 26 /* PPP software interrupt */
#include <net/ppp-comp.h>
#endif
+static int pppsioctl __P((struct ifnet *, int, caddr_t));
+static int pppoutput __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *, struct rtentry *));
static void ppp_requeue __P((struct ppp_softc *));
-static void ppp_outpkt __P((struct ppp_softc *));
static void ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd));
static void ppp_ccp_closed __P((struct ppp_softc *));
static void ppp_inproc __P((struct ppp_softc *, struct mbuf *));
sc->sc_relinq = NULL;
bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats));
#ifdef VJC
- MALLOC(sc->sc_comp, struct slcompress *, sizeof(struct slcompress),
+ MALLOC(sc->sc_comp, struct vjcompress *, sizeof(struct vjcompress),
M_DEVBUF, M_NOWAIT);
if (sc->sc_comp)
vj_compress_init(sc->sc_comp, -1);
}
/*
- * Deallocate a ppp unit. Must be called at splnet or higher.
+ * Deallocate a ppp unit. Must be called at splsoftnet or higher.
*/
void
pppdealloc(sc)
sc->sc_xc_state = NULL;
sc->sc_rc_state = NULL;
#endif /* PPP_COMPRESS */
+#ifdef PPP_FILTER
+ if (sc->sc_pass_filt.bf_insns != 0) {
+ FREE(sc->sc_pass_filt.bf_insns, M_DEVBUF);
+ sc->sc_pass_filt.bf_insns = 0;
+ sc->sc_pass_filt.bf_len = 0;
+ }
+ if (sc->sc_active_filt.bf_insns != 0) {
+ FREE(sc->sc_active_filt.bf_insns, M_DEVBUF);
+ sc->sc_active_filt.bf_insns = 0;
+ sc->sc_active_filt.bf_len = 0;
+ }
+#endif /* PPP_FILTER */
#ifdef VJC
if (sc->sc_comp != 0) {
FREE(sc->sc_comp, M_DEVBUF);
int
pppioctl(sc, cmd, data, flag, p)
struct ppp_softc *sc;
- u_long cmd;
+ int cmd;
caddr_t data;
int flag;
struct proc *p;
struct compressor **cp;
struct npioctl *npi;
time_t t;
+#ifdef PPP_FILTER
+ struct bpf_program *bp, *nbp;
+ struct bpf_insn *newcode, *oldcode;
+ int newcodelen;
+#endif /* PPP_FILTER */
#ifdef PPP_COMPRESS
u_char ccp_option[CCP_MAX_OPTION_LENGTH];
#endif
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
return (error);
flags = *(int *)data & SC_MASK;
- s = splnet();
+ s = splsoftnet();
#ifdef PPP_COMPRESS
if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
ppp_ccp_closed(sc);
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
return (error);
if (sc->sc_comp) {
- s = splnet();
+ s = splsoftnet();
vj_compress_init(sc->sc_comp, *(int *)data);
splx(s);
}
*/
error = 0;
if (odp->transmit) {
- s = splnet();
+ s = splsoftnet();
if (sc->sc_xc_state != NULL)
(*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
sc->sc_xcomp = *cp;
sc->sc_flags &= ~SC_COMP_RUN;
splx(s);
} else {
- s = splnet();
+ s = splsoftnet();
if (sc->sc_rc_state != NULL)
(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
sc->sc_rcomp = *cp;
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
return (error);
if (npi->mode != sc->sc_npmode[npx]) {
- s = splnet();
+ s = splsoftnet();
sc->sc_npmode[npx] = npi->mode;
if (npi->mode != NPMODE_QUEUE) {
ppp_requeue(sc);
break;
case PPPIOCGIDLE:
- s = splnet();
+ s = splsoftnet();
t = time.tv_sec;
((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent;
((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv;
splx(s);
break;
+#ifdef PPP_FILTER
+ case PPPIOCSPASS:
+ case PPPIOCSACTIVE:
+ nbp = (struct bpf_program *) data;
+ if ((unsigned) nbp->bf_len > BPF_MAXINSNS)
+ return EINVAL;
+ newcodelen = nbp->bf_len * sizeof(struct bpf_insn);
+ if (newcodelen != 0) {
+ MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK);
+ if (newcode == 0) {
+ return EINVAL; /* or sumpin */
+ }
+ if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode,
+ newcodelen)) != 0) {
+ FREE(newcode, M_DEVBUF);
+ return error;
+ }
+ if (!bpf_validate(newcode, nbp->bf_len)) {
+ FREE(newcode, M_DEVBUF);
+ return EINVAL;
+ }
+ } else
+ newcode = 0;
+ bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt;
+ oldcode = bp->bf_insns;
+ s = splimp();
+ bp->bf_len = nbp->bf_len;
+ bp->bf_insns = newcode;
+ splx(s);
+ if (oldcode != 0)
+ FREE(oldcode, M_DEVBUF);
+ break;
+#endif
+
default:
return (-1);
}
/*
* Process an ioctl request to the ppp network interface.
*/
-int
+static int
pppsioctl(ifp, cmd, data)
register struct ifnet *ifp;
- u_long cmd;
+ int cmd;
caddr_t data;
{
struct proc *p = curproc; /* XXX */
struct ip *ip;
struct ifqueue *ifq;
enum NPmode mode;
+ int len;
+ struct mbuf *m;
if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
|| ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
*cp++ = protocol & 0xff;
m0->m_len += PPP_HDRLEN;
+ len = 0;
+ for (m = m0; m != 0; m = m->m_next)
+ len += m->m_len;
+
if (sc->sc_flags & SC_LOG_OUTPKT) {
printf("ppp%d output: ", ifp->if_unit);
pppdumpm(m0);
}
if ((protocol & 0x8000) == 0) {
+#ifdef PPP_FILTER
+ /*
+ * Apply the pass and active filters to the packet,
+ * but only if it is a data packet.
+ */
+ *mtod(m0, u_char *) = 1; /* indicates outbound */
+ if (sc->sc_pass_filt.bf_insns != 0
+ && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0,
+ len, 0) == 0) {
+ error = 0; /* drop this packet */
+ goto bad;
+ }
+
+ /*
+ * Update the time we sent the most recent packet.
+ */
+ if (sc->sc_active_filt.bf_insns == 0
+ || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0))
+ sc->sc_last_sent = time.tv_sec;
+
+ *mtod(m0, u_char *) = address;
+#else
/*
* Update the time we sent the most recent data packet.
*/
sc->sc_last_sent = time.tv_sec;
+#endif /* PPP_FILTER */
}
#if NBPFILTER > 0
/*
* Put the packet on the appropriate queue.
*/
- s = splnet();
+ s = splsoftnet();
if (mode == NPMODE_QUEUE) {
/* XXX we should limit the number of packets on this queue */
*sc->sc_npqtail = m0;
/*
* After a change in the NPmode for some NP, move packets from the
* npqueue to the send queue or the fast queue as appropriate.
- * Should be called at splnet.
+ * Should be called at splsoftnet.
*/
static void
ppp_requeue(sc)
/*
* Transmitter has finished outputting some stuff;
- * remember to call sc->sc_start later at splnet.
+ * remember to call sc->sc_start later at splsoftnet.
*/
void
ppp_restart(sc)
/*
* Get a packet to send. This procedure is intended to be called at
- * splnet, since it may involve time-consuming operations such as
+ * splsoftnet, since it may involve time-consuming operations such as
* applying VJ compression, packet compression, address/control and/or
* protocol field compression to the packet.
*/
struct mbuf *m, *mp;
u_char *cp;
int address, control, protocol;
- int s;
/*
* Grab a packet to send: first try the fast queue, then the
for (mp = m; mp != NULL; mp = mp->m_next)
slen += mp->m_len;
clen = (*sc->sc_xcomp->compress)
- (sc->sc_xc_state, &mcomp, m, slen,
- (sc->sc_flags & SC_CCP_UP? sc->sc_if.if_mtu: 0));
+ (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN);
if (mcomp != NULL) {
- m_freem(m);
- m = mcomp;
- cp = mtod(m, u_char *);
- protocol = cp[3];
+ if (sc->sc_flags & SC_CCP_UP) {
+ /* Send the compressed packet instead of the original. */
+ m_freem(m);
+ m = mcomp;
+ cp = mtod(m, u_char *);
+ protocol = cp[3];
+ } else {
+ /* Can't transmit compressed packets until CCP is up. */
+ m_freem(mcomp);
+ }
}
}
#endif /* PPP_COMPRESS */
}
/*
- * Software interrupt routine, called at splnet.
+ * Software interrupt routine, called at splsoftnet.
*/
void
pppintr()
struct mbuf *m;
sc = ppp_softc;
- s = splnet();
+ s = splsoftnet();
for (i = 0; i < NPPP; ++i, ++sc) {
if (!(sc->sc_flags & SC_TBUSY)
&& (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head)) {
/*
* Process a received PPP packet, doing decompression as necessary.
- * Should be called at splnet.
+ * Should be called at splsoftnet.
*/
#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
TYPE_UNCOMPRESSED_TCP)
m->m_pkthdr.len = ilen;
m->m_pkthdr.rcvif = ifp;
- /*
- * Record the time that we received this packet.
- */
if ((proto & 0x8000) == 0) {
+#ifdef PPP_FILTER
+ /*
+ * See whether we want to pass this packet, and
+ * if it counts as link activity.
+ */
+ adrs = *mtod(m, u_char *); /* save address field */
+ *mtod(m, u_char *) = 0; /* indicate inbound */
+ if (sc->sc_pass_filt.bf_insns != 0
+ && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m,
+ ilen, 0) == 0) {
+ /* drop this packet */
+ m_freem(m);
+ return;
+ }
+ if (sc->sc_active_filt.bf_insns == 0
+ || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0))
+ sc->sc_last_recv = time.tv_sec;
+
+ *mtod(m, u_char *) = adrs;
+#else
+ /*
+ * Record the time that we received this packet.
+ */
sc->sc_last_recv = time.tv_sec;
+#endif /* PPP_FILTER */
}
#if NBPFILTER > 0