* Robert Olsson <robert@robur.slu.se> and Paul Mackerras.
*/
-/* $Id: if_ppp.c,v 1.3 1994/11/28 01:38:25 paulus Exp $ */
+/* $Id: if_ppp.c,v 1.9 1995/10/27 03:59:42 paulus Exp $ */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
#include "ppp.h"
#endif
void pppattach __P((void));
-int pppioctl __P((struct ppp_softc *sc, int cmd, caddr_t data, int flag,
- struct proc *));
+int pppioctl __P((struct ppp_softc *sc, int cmd, caddr_t data, int flag));
int pppoutput __P((struct ifnet *ifp, struct mbuf *m0,
struct sockaddr *dst));
int pppsioctl __P((struct ifnet *ifp, int cmd, caddr_t data));
void pppintr __P((void));
+static void ppp_requeue __P((struct ppp_softc *));
static void ppp_outpkt __P((struct ppp_softc *));
static int ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd));
static void ppp_ccp_closed __P((struct ppp_softc *));
extern struct compressor ppp_bsd_compress;
struct compressor *ppp_compressors[] = {
+#if DO_BSD_COMPRESS
&ppp_bsd_compress,
+#endif
NULL
};
#endif /* PPP_COMPRESS */
for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
if (sc->sc_xfer == pid) {
sc->sc_xfer = 0;
- break;
+ return sc;
}
- if (nppp >= NPPP)
- for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
- if (sc->sc_devp == NULL)
- break;
+ for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
+ if (sc->sc_devp == NULL)
+ break;
if (nppp >= NPPP)
return NULL;
sc->sc_flags = 0;
sc->sc_mru = PPP_MRU;
+ sc->sc_relinq = NULL;
#ifdef VJC
sl_compress_init(&sc->sc_comp);
#endif
#endif /* PPP_COMPRESS */
for (i = 0; i < NUM_NP; ++i)
sc->sc_npmode[i] = NPMODE_ERROR;
- sc->sc_if.if_flags |= IFF_RUNNING;
+ sc->sc_npqueue = NULL;
+ sc->sc_npqtail = &sc->sc_npqueue;
+ sc->sc_last_sent = sc->sc_last_recv = time.tv_sec;
return sc;
}
/*
- * Deallocate a ppp unit.
+ * Deallocate a ppp unit. Must be called at splnet or higher.
*/
void
pppdealloc(sc)
break;
m_freem(m);
}
+ while ((m = sc->sc_npqueue) != NULL) {
+ sc->sc_npqueue = m->m_act;
+ m_freem(m);
+ }
if (sc->sc_togo != NULL) {
m_freem(sc->sc_togo);
sc->sc_togo = NULL;
int cmd, flag;
{
struct proc *p = u.u_procp;
- int s, error, flags, mru, nb, npx;
+ int s, error, flags, mru, mtu, nb, npx;
struct ppp_option_data *odp;
struct compressor **cp;
struct npioctl *npi;
+ time_t t;
+#ifdef PPP_COMPRESS
u_char ccp_option[CCP_MAX_OPTION_LENGTH];
+#endif
switch (cmd) {
case FIONREAD:
return EPERM;
flags = *(int *)data & SC_MASK;
s = splnet();
+#ifdef PPP_COMPRESS
if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
ppp_ccp_closed(sc);
+#endif
splimp();
sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
splx(s);
*(int *)data = sc->sc_mru;
break;
+ /*
+ * PPPIOC[GS]MTU are implemented here, instead of supporting
+ * SIOC[GS]IFMTU in pppsioctl, because under Ultrix, we can't get an
+ * interface ioctl through to the interface until it has an IP
+ * address set.
+ */
+ case PPPIOCSMTU:
+ if (!suser())
+ return EPERM;
+ mtu = *(int *) data;
+ if (mtu <= 0 || mtu > PPP_MAXMRU)
+ return EINVAL;
+ s = splimp();
+ sc->sc_if.if_mtu = mtu;
+ splx(s);
+ break;
+
+ case PPPIOCGMTU:
+ *(int *) data = sc->sc_if.if_mtu;
+ break;
+
#ifdef VJC
case PPPIOCSMAXCID:
if (!suser())
* a compressor or decompressor.
*/
error = 0;
- s = splnet();
if (odp->transmit) {
+ s = splnet();
if (sc->sc_xc_state != NULL)
(*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
sc->sc_xcomp = *cp;
}
splimp();
sc->sc_flags &= ~SC_COMP_RUN;
+ splx(s);
} else {
+ s = splnet();
if (sc->sc_rc_state != NULL)
(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
sc->sc_rcomp = *cp;
}
splimp();
sc->sc_flags &= ~SC_DECOMP_RUN;
+ splx(s);
}
- splx(s);
return (error);
}
if (sc->sc_flags & SC_DEBUG)
if (!suser())
return EPERM;
if (npi->mode != sc->sc_npmode[npx]) {
- s = splimp();
+ s = splnet();
sc->sc_npmode[npx] = npi->mode;
- if (npi->mode != NPMODE_QUEUE)
+ if (npi->mode != NPMODE_QUEUE) {
+ ppp_requeue(sc);
(*sc->sc_start)(sc);
+ }
splx(s);
}
}
break;
+ case PPPIOCGIDLE:
+ s = splnet();
+ 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;
+
default:
return (-1);
}
register struct ifaddr *ifa = (struct ifaddr *)data;
register struct ifreq *ifr = (struct ifreq *)data;
struct ppp_stats *psp;
+#ifdef PPP_COMPRESS
struct ppp_comp_stats *pcp;
+#endif
int s = splimp(), error = 0;
switch (cmd) {
error = EAFNOSUPPORT;
break;
+/*
+ * Ioctls other than the above don't get through until the
+ * interface has its IP addresses set :-(
+ */
+
+#if 0
case SIOCSIFMTU:
if (!suser())
return EPERM;
case SIOCGIFMTU:
ifr->ifr_mtu = sc->sc_if.if_mtu;
break;
+#endif
case SIOCGPPPSTATS:
psp = &((struct ifpppstatsreq *) data)->stats;
/*
* Compute PPP header.
+ * We use the m_context field of the mbuf to indicate whether
+ * the packet should go on the fast queue.
*/
- ifq = &ifp->if_snd;
+ m0->m_context = 0;
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
control = PPP_UI;
protocol = PPP_IP;
mode = sc->sc_npmode[NP_IP];
-
+
/*
* If this is a TCP packet to or from an "interactive" port,
* put the packet on the fastq instead.
if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
register int p = ntohl(((int *)ip)[ip->ip_hl]);
if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
- ifq = &sc->sc_fastq;
+ m0->m_context = 1;
}
break;
#endif
/*
* Put the packet on the appropriate queue.
*/
- s = splimp(); /* splnet should be OK now */
- if (IF_QFULL(ifq)) {
- IF_DROP(ifq);
- splx(s);
- sc->sc_if.if_oerrors++;
- error = ENOBUFS;
- goto bad;
- }
- IF_ENQUEUE(ifq, m0);
-
- /*
- * Tell the device to send it out.
- */
- if (mode == NPMODE_PASS)
+ s = splnet();
+ if (mode == NPMODE_QUEUE) {
+ /* XXX we should limit the number of packets on this queue */
+ *sc->sc_npqtail = m0;
+ m0->m_act = NULL;
+ sc->sc_npqtail = &m0->m_act;
+ } else {
+ ifq = m0->m_context? &sc->sc_fastq: &ifp->if_snd;
+ if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
+ IF_DROP(ifq);
+ splx(s);
+ sc->sc_if.if_oerrors++;
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(ifq, m0);
(*sc->sc_start)(sc);
+ }
splx(s);
return (0);
}
/*
- * Get a packet to send. This procedure is intended to be called
- * at spltty()/splimp(), so it takes little time. If there isn't
- * a packet waiting to go out, it schedules a software interrupt
- * to prepare a new packet; the device start routine gets called
- * again when a packet is ready.
+ * 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.
+ */
+static void
+ppp_requeue(sc)
+ struct ppp_softc *sc;
+{
+ struct mbuf *m, **mpp;
+ struct ifqueue *ifq;
+ enum NPmode mode;
+
+ for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
+ switch (PPP_PROTOCOL(mtod(m, u_char *))) {
+ case PPP_IP:
+ mode = sc->sc_npmode[NP_IP];
+ break;
+ default:
+ mode = NPMODE_PASS;
+ }
+
+ switch (mode) {
+ case NPMODE_PASS:
+ /*
+ * This packet can now go on one of the queues to be sent.
+ */
+ *mpp = m->m_act;
+ m->m_act = NULL;
+ ifq = m->m_context? &sc->sc_fastq: &sc->sc_if.if_snd;
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq);
+ sc->sc_if.if_oerrors++;
+ } else
+ IF_ENQUEUE(ifq, m);
+ break;
+
+ case NPMODE_DROP:
+ case NPMODE_ERROR:
+ *mpp = m->m_act;
+ m_freem(m);
+ break;
+
+ case NPMODE_QUEUE:
+ mpp = &m->m_act;
+ break;
+ }
+ }
+ sc->sc_npqtail = mpp;
+}
+
+/*
+ * Get a packet to send. This procedure is intended to be called at
+ * spltty or splimp, so it takes little time. If there isn't a packet
+ * waiting to go out, it schedules a software interrupt to prepare a
+ * new packet; the device start routine gets called again when a
+ * packet is ready.
*/
struct mbuf *
ppp_dequeue(sc)
struct ppp_softc *sc;
{
struct mbuf *m;
+ int s = splimp();
m = sc->sc_togo;
if (m) {
*/
sc->sc_togo = NULL;
sc->sc_flags |= SC_TBUSY;
+ splx(s);
return m;
}
/*
*/
sc->sc_flags &= ~SC_TBUSY;
schednetisr(NETISR_PPP);
+ splx(s);
return NULL;
}
/*
- * Software interrupt routine, called at splnet().
+ * Software interrupt routine, called at splnet.
*/
void
pppintr()
int i, s;
struct mbuf *m;
+ s = splnet();
sc = ppp_softc;
for (i = 0; i < NPPP; ++i, ++sc) {
if (!(sc->sc_flags & SC_TBUSY) && sc->sc_togo == NULL
&& (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head))
ppp_outpkt(sc);
for (;;) {
+ s = splimp();
IF_DEQUEUE(&sc->sc_rawq, m);
+ splx(s);
if (m == NULL)
break;
ppp_inproc(sc, m);
}
}
+ splx(s);
}
/*
struct ppp_softc *sc;
{
int s;
- struct mbuf *m, *mp, **mpp;
+ struct mbuf *m, *mp;
u_char *cp;
int address, control, protocol;
- struct ifqueue *ifq;
enum NPmode mode;
/*
- * Scan through the send queues looking for a packet
- * which can be sent: first the fast queue, then the normal queue.
+ * Grab a packet to send: first try the fast queue, then the
+ * normal queue.
*/
- ifq = &sc->sc_fastq;
- for (;;) {
- mpp = &ifq->ifq_head;
- mp = NULL;
- while ((m = *mpp) != NULL) {
- switch (PPP_PROTOCOL(mtod(m, u_char *))) {
- case PPP_IP:
- mode = sc->sc_npmode[NP_IP];
- break;
- default:
- mode = NPMODE_PASS;
- }
- if (mode == NPMODE_PASS)
- break;
- switch (mode) {
- case NPMODE_DROP:
- case NPMODE_ERROR:
- *mpp = m->m_act;
- --ifq->ifq_len;
- m_freem(m);
- break;
- case NPMODE_QUEUE:
- mpp = &m->m_act;
- mp = m;
- break;
- }
- }
- if (m != NULL)
- break;
-
- if (ifq == &sc->sc_if.if_snd)
- break;
- /* Finished the fast queue; do the normal queue. */
- ifq = &sc->sc_if.if_snd;
- }
-
+ IF_DEQUEUE(&sc->sc_fastq, m);
+ if (m == NULL)
+ IF_DEQUEUE(&sc->sc_if.if_snd, m);
if (m == NULL)
return;
- if ((*mpp = m->m_act) == NULL)
- ifq->ifq_tail = mp;
- m->m_act = NULL;
- --ifq->ifq_len;
-
/*
* Extract the ppp header of the new packet.
* The ppp header will be in one mbuf.
protocol = PPP_PROTOCOL(cp);
switch (protocol) {
-#ifdef VJC
case PPP_IP:
+ /*
+ * Update the time we sent the most recent packet.
+ */
+ sc->sc_last_sent = time.tv_sec;
+
+#ifdef VJC
/*
* If the packet is a TCP/IP packet, see if we can compress it.
*/
cp[3] = protocol; /* update protocol in PPP header */
}
}
- break;
#endif /* VJC */
+ break;
#ifdef PPP_COMPRESS
case PPP_CCP:
--m->m_len;
}
- s = splimp();
sc->sc_togo = m;
(*sc->sc_start)(sc);
- splx(s);
}
#ifdef PPP_COMPRESS
u_char *dp, *ep;
struct mbuf *mp;
int slen, s;
- struct bsd_db *db;
/*
* Get a pointer to the data after the PPP header.
if (sc->sc_xc_state != NULL
&& (*sc->sc_xcomp->comp_init)
(sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
- sc->sc_if.if_unit, sc->sc_flags & SC_DEBUG)) {
+ sc->sc_if.if_unit, 0, sc->sc_flags & SC_DEBUG)) {
s = splimp();
sc->sc_flags |= SC_COMP_RUN;
splx(s);
if (sc->sc_rc_state != NULL
&& (*sc->sc_rcomp->decomp_init)
(sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
- sc->sc_if.if_unit, sc->sc_mru,
+ sc->sc_if.if_unit, 0, sc->sc_mru,
sc->sc_flags & SC_DEBUG)) {
s = splimp();
sc->sc_flags |= SC_DECOMP_RUN;
* PPP packet input routine.
* The caller has checked and removed the FCS and has inserted
* the address/control bytes and the protocol high byte if they
- * were omitted. Should be called at splimp/spltty.
+ * were omitted.
*/
void
ppppktin(sc, m, lost)
struct mbuf *m;
int lost;
{
+ int s = splimp();
+
m->m_context = lost;
IF_ENQUEUE(&sc->sc_rawq, m);
schednetisr(NETISR_PPP);
+ splx(s);
}
/*
* Process a received PPP packet, doing decompression as necessary.
+ * Should be called at splnet.
*/
#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
TYPE_UNCOMPRESSED_TCP)
sc->sc_if.if_ipackets++;
if (sc->sc_flags & SC_LOG_INPKT) {
+ ilen = 0;
+ for (mp = m; mp != NULL; mp = mp->m_next)
+ ilen += mp->m_len;
printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen);
pppdumpm(m);
}
&& !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) {
/* decompress this packet */
rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
- if (dmp != NULL) {
+ if (rv == DECOMP_OK) {
m_freem(m);
+ if (dmp == NULL) {
+ /* no error, but no decompressed packet produced */
+ return;
+ }
m = dmp;
cp = mtod(m, u_char *);
proto = PPP_PROTOCOL(cp);
} else {
- /* pass the compressed packet up to pppd, which may take
- CCP down or issue a Reset-Req. */
+ /*
+ * An error has occurred in decompression.
+ * Pass the compressed packet up to pppd, which may take
+ * CCP down or issue a Reset-Req.
+ */
if (sc->sc_flags & SC_DEBUG)
printf("ppp%d: decompress failed %d\n", sc->sc_if.if_unit, rv);
- s = splimp();
+ s = splhigh();
sc->sc_flags |= SC_VJ_RESET;
- switch (rv) {
- case DECOMP_OK:
- /* no error, but no decompressed packet produced */
- splx(s);
- m_freem(m);
- return;
- case DECOMP_ERROR:
+ if (rv == DECOMP_ERROR)
sc->sc_flags |= SC_DC_ERROR;
- break;
- case DECOMP_FATALERROR:
+ else
sc->sc_flags |= SC_DC_FERROR;
- break;
- }
splx(s);
}
bpf_mtap(sc->sc_bpf, m);
#endif
+ rv = 0;
switch (proto) {
#ifdef INET
case PPP_IP:
m->m_len -= PPP_HDRLEN;
schednetisr(NETISR_IP);
inq = &ipintrq;
+ sc->sc_last_recv = time.tv_sec; /* update time of last pkt rcvd */
break;
#endif
smp_lock(&lock->lk_ifqueue, LK_RETRY);
if (IF_QFULL(inq)) {
IF_DROP(inq);
- /* XXX should we unlock here? */
+ smp_unlock(&lock->lk_ifqueue);
splx(s);
if (sc->sc_flags & SC_DEBUG)
printf("ppp%d: input queue full\n", sc->sc_if.if_unit);