Commit 4e004d91 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

[NET]: Fix PPP async regression.

Fix PPP over async regression that the PPPoE changes caused.
Basically, PPP puts a zero length skbuff in the receive queue
as an error token, and the last change caused that to get flushed
as bad data.

Thanks to Diego Calleja Garcia, Matthew Harrell for validating this.
parent 2ca801b2
...@@ -1348,16 +1348,9 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -1348,16 +1348,9 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
struct channel *pch = chan->ppp; struct channel *pch = chan->ppp;
int proto; int proto;
if (pch == 0) if (pch == 0 || skb->len == 0) {
goto drop; kfree_skb(skb);
return;
/* need to have PPP header */
if (!pskb_may_pull(skb, 2)) {
if (pch->ppp) {
++pch->ppp->stats.rx_length_errors;
ppp_receive_error(pch->ppp);
}
goto drop;
} }
proto = PPP_PROTO(skb); proto = PPP_PROTO(skb);
...@@ -1374,10 +1367,6 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -1374,10 +1367,6 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
ppp_do_recv(pch->ppp, skb, pch); ppp_do_recv(pch->ppp, skb, pch);
} }
read_unlock_bh(&pch->upl); read_unlock_bh(&pch->upl);
return;
drop:
kfree_skb(skb);
return;
} }
/* Put a 0-length skb in the receive queue as an error indication */ /* Put a 0-length skb in the receive queue as an error indication */
...@@ -1409,13 +1398,23 @@ ppp_input_error(struct ppp_channel *chan, int code) ...@@ -1409,13 +1398,23 @@ ppp_input_error(struct ppp_channel *chan, int code)
static void static void
ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{ {
if (skb->len >= 2) {
#ifdef CONFIG_PPP_MULTILINK #ifdef CONFIG_PPP_MULTILINK
/* XXX do channel-level decompression here */ /* XXX do channel-level decompression here */
if (PPP_PROTO(skb) == PPP_MP) if (PPP_PROTO(skb) == PPP_MP)
ppp_receive_mp_frame(ppp, skb, pch); ppp_receive_mp_frame(ppp, skb, pch);
else else
#endif /* CONFIG_PPP_MULTILINK */ #endif /* CONFIG_PPP_MULTILINK */
ppp_receive_nonmp_frame(ppp, skb); ppp_receive_nonmp_frame(ppp, skb);
return;
}
if (skb->len > 0)
/* note: a 0-length skb is used as an error indication */
++ppp->stats.rx_length_errors;
kfree_skb(skb);
ppp_receive_error(ppp);
} }
static void static void
...@@ -1448,7 +1447,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1448,7 +1447,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err; goto err;
if (skb_tailroom(skb) < 124 || skb_is_nonlinear(skb) ) { if (skb_tailroom(skb) < 124) {
/* copy to a new sk_buff with more tailroom */ /* copy to a new sk_buff with more tailroom */
ns = dev_alloc_skb(skb->len + 128); ns = dev_alloc_skb(skb->len + 128);
if (ns == 0) { if (ns == 0) {
...@@ -1460,6 +1459,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1460,6 +1459,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
skb = ns; skb = ns;
} }
else if (!pskb_may_pull(skb, skb->len))
goto err;
len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2); len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2);
if (len <= 0) { if (len <= 0) {
printk(KERN_DEBUG "PPP: VJ decompression error\n"); printk(KERN_DEBUG "PPP: VJ decompression error\n");
...@@ -2033,12 +2035,12 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) ...@@ -2033,12 +2035,12 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
static void static void
ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
{ {
unsigned char *dp = skb->data + 2; unsigned char *dp;
int len; int len;
if (!pskb_may_pull(skb, CCP_HDRLEN + 2) if (!pskb_may_pull(skb, CCP_HDRLEN + 2))
|| skb->len < (len = CCP_LENGTH(dp)) + 2) return; /* no header */
return; /* too short */ dp = skb->data + 2;
switch (CCP_CODE(dp)) { switch (CCP_CODE(dp)) {
case CCP_CONFREQ: case CCP_CONFREQ:
...@@ -2071,10 +2073,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) ...@@ -2071,10 +2073,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
case CCP_CONFACK: case CCP_CONFACK:
if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN) if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN)
break; break;
if (!pskb_may_pull(skb, len = CCP_LENGTH(dp)) + 2)
if (!pskb_may_pull(skb, len)) return; /* too short */
break;
dp += CCP_HDRLEN; dp += CCP_HDRLEN;
len -= CCP_HDRLEN; len -= CCP_HDRLEN;
if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp)) if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment