-/* $OpenBSD: if_ppp.c,v 1.83 2015/05/13 10:42:46 jsg Exp $ */
+/* $OpenBSD: if_ppp.c,v 1.84 2015/06/03 00:50:09 dlg Exp $ */
/* $NetBSD: if_ppp.c,v 1.39 1997/05/17 21:11:59 christos Exp $ */
/*
int ppp_clone_create(struct if_clone *, int);
int ppp_clone_destroy(struct ifnet *);
-/*
- * Some useful mbuf macros not in mbuf.h.
- */
-#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
-
-#define M_DATASTART(m) \
- (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
- (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
-
-#define M_DATASIZE(m) \
- (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
- (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
+void ppp_pkt_list_init(struct ppp_pkt_list *, u_int);
+int ppp_pkt_enqueue(struct ppp_pkt_list *, struct ppp_pkt *);
+struct ppp_pkt *ppp_pkt_dequeue(struct ppp_pkt_list *);
+struct mbuf * ppp_pkt_mbuf(struct ppp_pkt *);
/*
* We steal two bits in the mbuf m_flags, to mark high-priority packets
IFQ_SET_MAXLEN(&sc->sc_if.if_snd, IFQ_MAXLEN);
mq_init(&sc->sc_inq, IFQ_MAXLEN, IPL_NET);
IFQ_SET_MAXLEN(&sc->sc_fastq, IFQ_MAXLEN);
- IFQ_SET_MAXLEN(&sc->sc_rawq, IFQ_MAXLEN);
+ ppp_pkt_list_init(&sc->sc_rawq, IFQ_MAXLEN);
IFQ_SET_READY(&sc->sc_if.if_snd);
if_attach(&sc->sc_if);
if_alloc_sadl(&sc->sc_if);
void
pppdealloc(struct ppp_softc *sc)
{
+ struct ppp_pkt *pkt;
struct mbuf *m;
splsoftassert(IPL_SOFTNET);
sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
sc->sc_devp = NULL;
sc->sc_xfer = 0;
- for (;;) {
- IF_DEQUEUE(&sc->sc_rawq, m);
- if (m == NULL)
- break;
- m_freem(m);
- }
+ while ((pkt = ppp_pkt_dequeue(&sc->sc_rawq)) != NULL)
+ ppp_pkt_free(pkt);
while ((m = mq_dequeue(&sc->sc_inq)) != NULL)
m_freem(m);
for (;;) {
pppintr(void)
{
struct ppp_softc *sc;
- int s, s2;
+ int s;
+ struct ppp_pkt *pkt;
struct mbuf *m;
splsoftassert(IPL_SOFTNET);
- s = splsoftnet(); /* XXX - what's the point of this? see comment above */
LIST_FOREACH(sc, &ppp_softc_list, sc_list) {
if (!(sc->sc_flags & SC_TBUSY)
&& (!IFQ_IS_EMPTY(&sc->sc_if.if_snd) ||
!IFQ_IS_EMPTY(&sc->sc_fastq))) {
- s2 = splnet();
+ s = splnet();
sc->sc_flags |= SC_TBUSY;
- splx(s2);
+ splx(s);
(*sc->sc_start)(sc);
}
- while (!IFQ_IS_EMPTY(&sc->sc_rawq)) {
- s2 = splnet();
- IF_DEQUEUE(&sc->sc_rawq, m);
- splx(s2);
+ while ((pkt = ppp_pkt_dequeue(&sc->sc_rawq)) != NULL) {
+ m = ppp_pkt_mbuf(pkt);
if (m == NULL)
- break;
+ continue;
ppp_inproc(sc, m);
}
}
- splx(s);
}
#ifdef PPP_COMPRESS
* were omitted.
*/
void
-ppppktin(struct ppp_softc *sc, struct mbuf *m, int lost)
+ppppktin(struct ppp_softc *sc, struct ppp_pkt *pkt, int lost)
{
- int s = splnet();
-
- if (lost)
- m->m_flags |= M_ERRMARK;
- IF_ENQUEUE(&sc->sc_rawq, m);
- schednetisr(NETISR_PPP);
- splx(s);
+ pkt->p_hdr.ph_errmark = lost;
+ if (ppp_pkt_enqueue(&sc->sc_rawq, pkt) == 0)
+ schednetisr(NETISR_PPP);
}
/*
}
#endif /* VJC */
- /*
- * If the packet will fit in a header mbuf, don't waste a
- * whole cluster on it.
- */
- if (ilen <= MHLEN && M_IS_CLUSTER(m)) {
- MGETHDR(mp, M_DONTWAIT, MT_DATA);
- if (mp != NULL) {
- m_copydata(m, 0, ilen, mtod(mp, caddr_t));
- m_freem(m);
- m = mp;
- m->m_len = ilen;
- }
- }
m->m_pkthdr.len = ilen;
m->m_pkthdr.rcvif = ifp;
sc = ifp->if_softc;
(*sc->sc_start)(sc);
}
+
+void
+ppp_pkt_list_init(struct ppp_pkt_list *pl, u_int limit)
+{
+ mtx_init(&pl->pl_mtx, IPL_TTY);
+ pl->pl_head = pl->pl_tail = NULL;
+ pl->pl_count = 0;
+ pl->pl_limit = limit;
+}
+
+int
+ppp_pkt_enqueue(struct ppp_pkt_list *pl, struct ppp_pkt *pkt)
+{
+ int drop = 0;
+
+ mtx_enter(&pl->pl_mtx);
+ if (pl->pl_count < pl->pl_limit) {
+ if (pl->pl_tail == NULL)
+ pl->pl_head = pl->pl_tail = pkt;
+ else {
+ PKT_NEXTPKT(pl->pl_tail) = pkt;
+ pl->pl_tail = pkt;
+ }
+ PKT_NEXTPKT(pkt) = NULL;
+ pl->pl_count++;
+ } else
+ drop = 1;
+ mtx_leave(&pl->pl_mtx);
+
+ if (drop)
+ ppp_pkt_free(pkt);
+
+ return (drop);
+}
+
+struct ppp_pkt *
+ppp_pkt_dequeue(struct ppp_pkt_list *pl)
+{
+ struct ppp_pkt *pkt;
+
+ mtx_enter(&pl->pl_mtx);
+ pkt = pl->pl_head;
+ if (pkt != NULL) {
+ pl->pl_head = PKT_NEXTPKT(pkt);
+ if (pl->pl_head == NULL)
+ pl->pl_tail = NULL;
+
+ pl->pl_count--;
+ }
+ mtx_leave(&pl->pl_mtx);
+
+ return (pkt);
+}
+
+struct mbuf *
+ppp_pkt_mbuf(struct ppp_pkt *pkt0)
+{
+ extern struct pool ppp_pkts;
+ struct mbuf *m0 = NULL, **mp = &m0, *m;
+ struct ppp_pkt *pkt = pkt0;
+ size_t len = 0;
+
+ do {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ goto fail;
+
+ MEXTADD(m, pkt, sizeof(*pkt), M_EXTWR,
+ m_extfree_pool, &ppp_pkts);
+ m->m_data += sizeof(pkt->p_hdr);
+ m->m_len = PKT_LEN(pkt);
+
+ len += m->m_len;
+
+ *mp = m;
+ mp = &m->m_next;
+
+ pkt = PKT_NEXT(pkt);
+ } while (pkt != NULL);
+
+ m0->m_pkthdr.len = len;
+ if (pkt0->p_hdr.ph_errmark)
+ m0->m_flags |= M_ERRMARK;
+
+ return (m0);
+
+fail:
+ m_freem(m0);
+ ppp_pkt_free(pkt0);
+ return (NULL);
+}
+
#endif /* NPPP > 0 */
-/* $OpenBSD: if_pppvar.h,v 1.16 2015/04/10 13:58:20 dlg Exp $ */
+/* $OpenBSD: if_pppvar.h,v 1.17 2015/06/03 00:50:09 dlg Exp $ */
/* $NetBSD: if_pppvar.h,v 1.5 1997/01/03 07:23:29 mikel Exp $ */
/*
* if_pppvar.h - private structures and declarations for PPP.
#define NP_IP 0 /* Internet Protocol */
#define NUM_NP 1 /* Number of NPs. */
+struct ppp_pkt;
+
+struct ppp_pkt_list {
+ struct mutex pl_mtx;
+ struct ppp_pkt *pl_head;
+ struct ppp_pkt *pl_tail;
+ u_int pl_count;
+ u_int pl_limit;
+};
+
/*
* Structure describing each ppp unit.
*/
void (*sc_relinq)(struct ppp_softc *); /* relinquish ifunit */
u_int16_t sc_mru; /* max receive unit */
pid_t sc_xfer; /* used in transferring unit */
- struct ifqueue sc_rawq; /* received packets */
+ struct ppp_pkt_list sc_rawq; /* received packets */
struct mbuf_queue sc_inq; /* queue of input packets for daemon */
struct ifqueue sc_fastq; /* interactive output packet q */
struct mbuf *sc_togo; /* output packet ready to go */
ext_accm sc_asyncmap; /* async control character map */
u_int32_t sc_rasyncmap; /* receive async control char map */
struct mbuf *sc_outm; /* mbuf chain currently being output */
- struct mbuf *sc_m; /* pointer to input mbuf chain */
- struct mbuf *sc_mc; /* pointer to current input mbuf */
- char *sc_mp; /* ptr to next char in input mbuf */
+ struct ppp_pkt *sc_pkt; /* pointer to input pkt chain */
+ struct ppp_pkt *sc_pktc; /* pointer to current input pkt */
+ uint8_t *sc_pktp; /* ptr to next char in input pkt */
u_int16_t sc_ilen; /* length of input packet so far */
u_int16_t sc_fcs; /* FCS so far (input) */
u_int16_t sc_outfcs; /* FCS so far for output packet */
};
#ifdef _KERNEL
+
+struct ppp_pkt_hdr {
+ struct ppp_pkt *ph_next; /* next in pkt chain */
+ struct ppp_pkt *ph_pkt; /* prev in chain or next in list */
+ uint16_t ph_len;
+ uint16_t ph_errmark;
+};
+
+struct ppp_pkt {
+ struct ppp_pkt_hdr p_hdr;
+ uint8_t p_buf[MCLBYTES - sizeof(struct ppp_pkt_hdr)];
+};
+
+void ppp_pkt_free(struct ppp_pkt *);
+
+#define PKT_NEXT(_p) ((_p)->p_hdr.ph_next)
+#define PKT_PREV(_p) ((_p)->p_hdr.ph_pkt)
+#define PKT_NEXTPKT(_p) ((_p)->p_hdr.ph_pkt)
+#define PKT_LEN(_p) ((_p)->p_hdr.ph_len)
+
extern struct ppp_softc ppp_softc[];
struct ppp_softc *pppalloc(pid_t pid);
void pppdealloc(struct ppp_softc *sc);
int pppioctl(struct ppp_softc *sc, u_long cmd, caddr_t data,
int flag, struct proc *p);
-void ppppktin(struct ppp_softc *sc, struct mbuf *m, int lost);
+void ppppktin(struct ppp_softc *sc, struct ppp_pkt *pkt, int lost);
struct mbuf *ppp_dequeue(struct ppp_softc *sc);
void ppp_restart(struct ppp_softc *sc);
int pppoutput(struct ifnet *, struct mbuf *,
-/* $OpenBSD: ppp_tty.c,v 1.32 2015/04/10 13:58:20 dlg Exp $ */
+/* $OpenBSD: ppp_tty.c,v 1.33 2015/06/03 00:50:09 dlg Exp $ */
/* $NetBSD: ppp_tty.c,v 1.12 1997/03/24 21:23:10 christos Exp $ */
/*
#include <sys/conf.h>
#include <sys/vnode.h>
#include <sys/systm.h>
+#include <sys/rwlock.h>
+#include <sys/pool.h>
#include <net/if.h>
#include <net/if_var.h>
void pppasyncctlp(struct ppp_softc *);
void pppasyncrelinq(struct ppp_softc *);
void ppp_timeout(void *);
-void pppgetm(struct ppp_softc *sc);
+void ppppkt(struct ppp_softc *sc);
void pppdumpb(u_char *b, int l);
void ppplogchar(struct ppp_softc *, int);
-/*
- * Some useful mbuf macros not in mbuf.h.
- */
-#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
+struct rwlock ppp_pkt_init = RWLOCK_INITIALIZER("ppppktini");
+struct pool ppp_pkts;
-#define M_DATASTART(m) \
- (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
- (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
-
-#define M_DATASIZE(m) \
- (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
- (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
+#define PKT_MAXLEN(_sc) ((_sc)->sc_mru + PPP_HDRLEN + PPP_FCSLEN)
/*
* Does c need to be escaped?
if ((error = suser(p, 0)) != 0)
return (error);
+ rw_enter_write(&ppp_pkt_init);
+ if (ppp_pkts.pr_size == 0) {
+ extern struct kmem_pa_mode kp_dma_contig;
+
+ pool_init(&ppp_pkts, sizeof(struct ppp_pkt), 0, 0, 0, "ppppkts", NULL);
+ pool_setipl(&ppp_pkts, IPL_TTY); /* IPL_SOFTTTY */
+ pool_set_constraints(&ppp_pkts, &kp_dma_contig);
+ }
+ rw_exit_write(&ppp_pkt_init);
+
s = spltty();
if (tp->t_line == PPPDISC) {
timeout_set(&sc->sc_timo, ppp_timeout, sc);
sc->sc_ilen = 0;
- sc->sc_m = NULL;
+ sc->sc_pkt = NULL;
bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
sc->sc_asyncmap[0] = 0xffffffff;
sc->sc_asyncmap[3] = 0x60000000;
sc->sc_ctlp = pppasyncctlp;
sc->sc_relinq = pppasyncrelinq;
sc->sc_outm = NULL;
- pppgetm(sc);
+ ppppkt(sc);
sc->sc_if.if_flags |= IFF_RUNNING;
sc->sc_if.if_baudrate = tp->t_ospeed;
m_freem(sc->sc_outm);
sc->sc_outm = NULL;
}
- if (sc->sc_m) {
- m_freem(sc->sc_m);
- sc->sc_m = NULL;
+ if (sc->sc_pkt != NULL) {
+ ppp_pkt_free(sc->sc_pkt);
+ sc->sc_pkt = sc->sc_pktc = NULL;
}
if (sc->sc_flags & SC_TIMEOUT) {
timeout_del(&sc->sc_timo);
default:
error = pppioctl(sc, cmd, data, flag, p);
if (error == 0 && cmd == PPPIOCSMRU)
- pppgetm(sc);
+ ppppkt(sc);
}
return error;
* Allocate enough mbuf to handle current MRU.
*/
void
-pppgetm(struct ppp_softc *sc)
+ppppkt(struct ppp_softc *sc)
{
- struct mbuf *m, **mp;
+ struct ppp_pkt **pktp, *pkt;
int len;
int s;
s = spltty();
- mp = &sc->sc_m;
- for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
- if ((m = *mp) == NULL) {
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == NULL)
+ pktp = &sc->sc_pkt;
+ for (len = PKT_MAXLEN(sc); len > 0; len -= sizeof(pkt->p_buf)) {
+ pkt = *pktp;
+ if (pkt == NULL) {
+ pkt = pool_get(&ppp_pkts, PR_NOWAIT);
+ if (pkt == NULL)
break;
- *mp = m;
- MCLGET(m, M_DONTWAIT);
+ PKT_NEXT(pkt) = NULL;
+ PKT_PREV(pkt) = *pktp;
+ PKT_LEN(pkt) = 0;
+ *pktp = pkt;
}
- len -= M_DATASIZE(m);
- mp = &m->m_next;
+ pktp = &PKT_NEXT(pkt);
}
splx(s);
}
+void
+ppp_pkt_free(struct ppp_pkt *pkt)
+{
+ struct ppp_pkt *next;
+
+ while (pkt != NULL) {
+ next = PKT_NEXT(pkt);
+ pool_put(&ppp_pkts, pkt);
+ pkt = next;
+ }
+}
+
/*
* tty interface receiver interrupt.
*/
pppinput(int c, struct tty *tp)
{
struct ppp_softc *sc;
- struct mbuf *m;
+ struct ppp_pkt *pkt;
int ilen, s;
sc = (struct ppp_softc *) tp->t_sc;
}
/*
- * Remove FCS trailer. Somewhat painful...
+ * Remove FCS trailer.
*/
ilen -= 2;
- if (--sc->sc_mc->m_len == 0) {
- for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
- ;
- sc->sc_mc = m;
+ pkt = sc->sc_pktc;
+ if (--PKT_LEN(pkt) == 0) {
+ pkt = PKT_PREV(pkt);
+ sc->sc_pktc = pkt;
}
- sc->sc_mc->m_len--;
+ PKT_LEN(pkt)--;
/* excise this mbuf chain */
- m = sc->sc_m;
- sc->sc_m = sc->sc_mc->m_next;
- sc->sc_mc->m_next = NULL;
+ pkt = sc->sc_pkt;
+ sc->sc_pkt = sc->sc_pktc = PKT_NEXT(sc->sc_pktc);
+ PKT_NEXT(pkt) = NULL;
- ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
+ ppppktin(sc, pkt, sc->sc_flags & SC_PKTLOST);
if (sc->sc_flags & SC_PKTLOST) {
s = spltty();
sc->sc_flags &= ~SC_PKTLOST;
splx(s);
}
- pppgetm(sc);
+ ppppkt(sc);
return 0;
}
*/
if (sc->sc_ilen == 0) {
/* reset the first input mbuf */
- if (sc->sc_m == NULL) {
- pppgetm(sc);
- if (sc->sc_m == NULL) {
+ if (sc->sc_pkt == NULL) {
+ ppppkt(sc);
+ if (sc->sc_pkt == NULL) {
if (sc->sc_flags & SC_DEBUG)
printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
goto flush;
}
}
- m = sc->sc_m;
- m->m_len = 0;
- m->m_data = M_DATASTART(sc->sc_m);
- sc->sc_mc = m;
- sc->sc_mp = mtod(m, char *);
+ pkt = sc->sc_pkt;
+ PKT_LEN(pkt) = 0;
+ sc->sc_pktc = pkt;
+ sc->sc_pktp = pkt->p_buf;
sc->sc_fcs = PPP_INITFCS;
if (c != PPP_ALLSTATIONS) {
if (sc->sc_flags & SC_REJ_COMP_AC) {
sc->sc_if.if_xname, c);
goto flush;
}
- *sc->sc_mp++ = PPP_ALLSTATIONS;
- *sc->sc_mp++ = PPP_UI;
+ *sc->sc_pktp++ = PPP_ALLSTATIONS;
+ *sc->sc_pktp++ = PPP_UI;
sc->sc_ilen += 2;
- m->m_len += 2;
+ PKT_LEN(pkt) += 2;
}
}
if (sc->sc_ilen == 1 && c != PPP_UI) {
}
if (sc->sc_ilen == 2 && (c & 1) == 1) {
/* a compressed protocol */
- *sc->sc_mp++ = 0;
+ *sc->sc_pktp++ = 0;
sc->sc_ilen++;
- sc->sc_mc->m_len++;
+ PKT_LEN(sc->sc_pktc)++;
}
if (sc->sc_ilen == 3 && (c & 1) == 0) {
if (sc->sc_flags & SC_DEBUG)
printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
- (sc->sc_mp[-1] << 8) + c);
+ (sc->sc_pktp[-1] << 8) + c);
goto flush;
}
/* packet beyond configured mru? */
- if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
+ if (++sc->sc_ilen > PKT_MAXLEN(sc)) {
if (sc->sc_flags & SC_DEBUG)
printf("%s: packet too big\n", sc->sc_if.if_xname);
goto flush;
}
- /* is this mbuf full? */
- m = sc->sc_mc;
- if (M_TRAILINGSPACE(m) <= 0) {
- if (m->m_next == NULL) {
- pppgetm(sc);
- if (m->m_next == NULL) {
+ /* is this packet full? */
+ pkt = sc->sc_pktc;
+ if (PKT_LEN(pkt) >= sizeof(pkt->p_buf)) {
+ if (PKT_NEXT(pkt) == NULL) {
+ ppppkt(sc);
+ if (PKT_NEXT(pkt) == NULL) {
if (sc->sc_flags & SC_DEBUG)
- printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
+ printf("%s: too few input packets!\n", sc->sc_if.if_xname);
goto flush;
}
}
- sc->sc_mc = m = m->m_next;
- m->m_len = 0;
- m->m_data = M_DATASTART(m);
- sc->sc_mp = mtod(m, char *);
+ sc->sc_pktc = pkt = PKT_NEXT(pkt);
+ PKT_LEN(pkt) = 0;
+ sc->sc_pktp = pkt->p_buf;
}
- ++m->m_len;
- *sc->sc_mp++ = c;
+ ++PKT_LEN(pkt);
+ *sc->sc_pktp++ = c;
sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
return 0;