* 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.4 1994/12/08 00:32:59 paulus Exp $ */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
#include "ppp.h"
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 *));
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;
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_nextpkt;
+ m_freem(m);
+ }
if (sc->sc_togo != NULL) {
m_freem(sc->sc_togo);
sc->sc_togo = NULL;
if (npi->mode != sc->sc_npmode[npx]) {
s = splimp();
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);
}
}
/*
* 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:
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)
+ if (mode == NPMODE_QUEUE) {
+ /* XXX we should limit the number of packets on this queue */
+ *sc->sc_npqtail = m0;
+ m0->m_nextpkt = NULL;
+ sc->sc_npqtail = &m0->m_nextpkt;
+ } else {
+ ifq = m0->m_context? &sc->sc_fastq: &ifp->if_snd;
+ if (IF_QFULL(ifq)) {
+ 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);
return (error);
}
+/*
+ * 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 splimp (actually splnet would probably suffice).
+ */
+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_nextpkt;
+ m->m_nextpkt = NULL;
+ ifq = (m->m_flags & M_HIGHPRI)? &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_nextpkt;
+ m_freem(m);
+ break;
+
+ case NPMODE_QUEUE:
+ mpp = &m->m_nextpkt;
+ break;
+ }
+ }
+ sc->sc_npqtail = mpp;
+}
+
/*
* Get a packet to send. This procedure is intended to be called
* at spltty()/splimp(), so it takes little time. If there isn't
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;
}
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
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.
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);
}
/*
struct ppp_softc *sc;
struct mbuf *m;
{
- struct ifqueue *inq, *lock;
+ struct ifqueue *inq;
int s, ilen, xlen, proto, rv;
u_char *cp, adrs, ctrl;
struct mbuf *mp, *dmp, *pc;
bpf_mtap(sc->sc_bpf, m);
#endif
+ rv = 0;
switch (proto) {
#ifdef INET
case PPP_IP:
/*
- * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
+ * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
+ * tty devices.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
* Robert Olsson <robert@robur.slu.se> and Paul Mackerras.
*/
-/* $Id: ppp_tty.c,v 1.2 1994/11/28 01:38:59 paulus Exp $ */
+/* $Id: ppp_tty.c,v 1.3 1994/12/08 00:32:59 paulus Exp $ */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
#include "ppp.h"
static u_short pppfcs __P((u_short fcs, u_char *cp, int len));
static void pppasyncstart __P((struct ppp_softc *));
static void pppasyncctlp __P((struct ppp_softc *));
+static void pppasyncrelinq __P((struct ppp_softc *));
static void pppgetm __P((struct ppp_softc *sc));
static void pppdumpb __P((u_char *b, int l));
static void ppplogchar __P((struct ppp_softc *, int));
if ((sc = pppalloc(p->p_pid)) == NULL)
return ENXIO;
- if (sc->sc_outm != NULL) {
- m_freem(sc->sc_outm);
- sc->sc_outm = NULL;
- }
-
- pppgetm(sc);
+ if (sc->sc_relinq)
+ (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
+ s = splimp();
sc->sc_ilen = 0;
+ sc->sc_m = NULL;
bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
sc->sc_asyncmap[0] = 0xffffffff;
sc->sc_asyncmap[3] = 0x60000000;
sc->sc_devp = (void *) tp;
sc->sc_start = pppasyncstart;
sc->sc_ctlp = pppasyncctlp;
+ sc->sc_relinq = pppasyncrelinq;
+ sc->sc_outm = NULL;
+ pppgetm(sc);
+ sc->sc_if.if_flags |= IFF_RUNNING;
tp->t_sc = (caddr_t) sc;
ttyflush(tp, FREAD | FWRITE);
+ splx(s);
return (0);
}
ttywflush(tp);
s = splimp(); /* paranoid; splnet probably ok */
tp->t_line = 0;
- sc = (struct ppp_softc *)tp->t_sc;
+ sc = (struct ppp_softc *) tp->t_sc;
if (sc != NULL) {
tp->t_sc = NULL;
if (tp == (struct tty *) sc->sc_devp) {
- m_freem(sc->sc_outm);
- sc->sc_outm = NULL;
- m_freem(sc->sc_m);
- sc->sc_m = NULL;
+ pppasyncrelinq(sc);
pppdealloc(sc);
}
}
return 0;
}
+/*
+ * Relinquish the interface unit to another device.
+ */
+static void
+pppasyncrelinq(sc)
+ struct ppp_softc *sc;
+{
+ int s;
+
+ s = splimp();
+ if (sc->sc_outm) {
+ m_freem(sc->sc_outm);
+ sc->sc_outm = NULL;
+ }
+ if (sc->sc_m) {
+ m_freem(sc->sc_m);
+ sc->sc_m = NULL;
+ }
+ splx(s);
+}
+
/*
* Line specific (tty) read routine.
*/
int cmd, flag;
{
struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
- int error;
+ int error, s;
if (sc == NULL || tp != (struct tty *) sc->sc_devp)
return -1;
case PPPIOCSXASYNCMAP:
if (!suser())
return EPERM;
+ s = spltty();
bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
+ splx(s);
break;
case PPPIOCGXASYNCMAP:
register struct ppp_softc *sc;
{
register struct tty *tp = (struct tty *) sc->sc_devp;
+ int s;
+ s = splimp();
pppstart(tp);
+ splx(s);
}
/*
* Get another packet to be sent.
*/
m = ppp_dequeue(sc);
- if (m == NULL)
+ if (m == NULL) {
+ if (tp->t_oproc != NULL)
+ (*tp->t_oproc)(tp);
return;
+ }
/*
* The extra PPP_FLAG will start up a new packet, and thus
register struct ppp_softc *sc;
struct mbuf *m;
int ilen;
+ extern int tk_nin;
tk_nin++;
sc = (struct ppp_softc *) tp->t_sc;
if (sc == NULL || tp != (struct tty *) sc->sc_devp)
return;
+ s = spltty();
sc->sc_bytesrcvd++;
c &= 0xff;
sc->sc_if.if_ierrors++;
} else
sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
+ splx(s);
return;
}
sc->sc_if.if_ierrors++;
sc->sc_flags |= SC_PKTLOST;
}
+ splx(s);
return;
}
sc->sc_flags &= ~SC_PKTLOST;
pppgetm(sc);
+ splx(s);
return;
}
if (sc->sc_flags & SC_FLUSH) {
if (sc->sc_flags & SC_LOG_FLUSH)
ppplogchar(sc, c);
+ splx(s);
return;
}
- if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
+ if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) {
+ splx(s);
return;
+ }
if (sc->sc_flags & SC_ESCAPED) {
sc->sc_flags &= ~SC_ESCAPED;
c ^= PPP_TRANS;
} else if (c == PPP_ESCAPE) {
sc->sc_flags |= SC_ESCAPED;
+ splx(s);
return;
}
++m->m_len;
*sc->sc_mp++ = c;
sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
+ splx(s);
return;
flush:
if (sc->sc_flags & SC_LOG_FLUSH)
ppplogchar(sc, c);
}
+ splx(s);
}
#define MAX_DUMP_BYTES 128