Subject: kern/30393: PF/ALTQ does not work on ppp(4) interfaces
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <carton@Ivy.NET>
List: netbsd-bugs
Date: 06/01/2005 21:38:00
>Number: 30393
>Category: kern
>Synopsis: PF/ALTQ does not work on ppp(4) interfaces
>Confidential: no
>Severity: serious
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Jun 01 21:38:00 +0000 2005
>Originator: Miles Nordin
>Release: NetBSD 2.0.2_STABLE, pflkm-20050118
>Organization:
Ivy Ministries
>Environment:
System: NetBSD castrovalva 2.0.2_STABLE NetBSD 2.0.2_STABLE (CASTROVALVA-$Revision: 1.10 $) #0: Wed Apr 27 23:41:50 EDT 2005 carton@castrovalva:/scratch/src/sys/arch/alpha/compile/CASTROVALVA alpha
Architecture: alpha
Machine: alpha
>Description:
When running ALTQ on a PPP interface, I get on the console:
altq: packet for ppp0 does not have pkthdr
and in /var/log/messages:
May 31 21:37:04 ezln pppd[3455]: write: No buffer space available
pppd is unable to bring up a session. If I enable altq after a session is
up, the session dies after a few minutes.
>How-To-Repeat:
patch kernel with altq.diff included with pflkm
install security/pflkm and load the module
enable altq on ppp0
try to use pppd to establish a session on ppp0. It'll fail for being unable
to send LCP messages.
>Fix:
I tracked it down to net/ppp_tty.c, which is allocating the mbuf chain
that doesn't start with a header. It's allocated I think when someone
write()s to a tty that is in pppdisc, like for LCP and other control
messages. This fixes it for me:
Index: ppp_tty.c
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sys/net/ppp_tty.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 ppp_tty.c
--- ppp_tty.c 12 Dec 2003 11:38:22 -0000 1.1.1.5
+++ ppp_tty.c 1 Jun 2005 01:42:21 -0000
@@ -373,7 +373,7 @@
int flag;
{
struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
- struct mbuf *m, *m0, **mp;
+ struct mbuf *m, *m0;
struct sockaddr dst;
int len, error;
@@ -386,28 +386,34 @@
if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
uio->uio_resid < PPP_HDRLEN)
return (EMSGSIZE);
- for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
- m = m_get(M_WAIT, MT_DATA);
- if ((*mp = m) == NULL) {
- m_freem(m0);
- return (ENOBUFS);
- }
+ MGETHDR(m0, M_WAIT, MT_DATA);
+ m0->m_len = 0;
+ m0->m_pkthdr.len = uio->uio_resid;
+ m0->m_pkthdr.rcvif = (struct ifnet *)0;
+ for (m = m0; uio->uio_resid; m = m->m_next) {
m->m_len = 0;
if (uio->uio_resid >= MCLBYTES / 2)
MCLGET(m, M_DONTWAIT);
len = M_TRAILINGSPACE(m);
- if (len > uio->uio_resid)
+ if (len >= uio->uio_resid) {
len = uio->uio_resid;
- if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
- m_freem(m0);
- return (error);
- }
- m->m_len = len;
+ if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
+ m_freem(m0);
+ return (error);
+ }
+ m->m_len = len;
+ } else {
+ if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
+ m_freem(m0);
+ return (error);
+ }
+ m->m_len = len;
+ MGET(m->m_next, M_WAIT, MT_DATA);
+ }
}
dst.sa_family = AF_UNSPEC;
bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
- m0->m_data += PPP_HDRLEN;
- m0->m_len -= PPP_HDRLEN;
+ m_adj(m0, PPP_HDRLEN);
return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
}