Commit b7911d4a authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Hideaki Yoshifuji

[NET]: Convert PPPoE to new style protocol.

parent 8df86fa2
...@@ -1348,11 +1348,18 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -1348,11 +1348,18 @@ 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 || skb->len == 0) { if (pch == 0)
kfree_skb(skb); goto drop;
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);
read_lock_bh(&pch->upl); read_lock_bh(&pch->upl);
if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) { if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) {
...@@ -1367,6 +1374,10 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -1367,6 +1374,10 @@ 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 */
...@@ -1398,23 +1409,13 @@ ppp_input_error(struct ppp_channel *chan, int code) ...@@ -1398,23 +1409,13 @@ 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
...@@ -1446,7 +1447,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1446,7 +1447,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* decompress VJ compressed packets */ /* decompress VJ compressed packets */
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) {
if (skb_tailroom(skb) < 124 || skb_is_nonlinear(skb) ) {
/* 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) {
...@@ -1474,6 +1476,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1474,6 +1476,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
case PPP_VJC_UNCOMP: case PPP_VJC_UNCOMP:
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err; goto err;
/* Until we fix the decompressor need to make sure
* data portion is linear.
*/
if (!pskb_may_pull(skb, skb->len))
goto err;
if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) { if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) {
printk(KERN_ERR "PPP: VJ uncompressed error\n"); printk(KERN_ERR "PPP: VJ uncompressed error\n");
goto err; goto err;
...@@ -1551,6 +1560,12 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1551,6 +1560,12 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
struct sk_buff *ns; struct sk_buff *ns;
int len; int len;
/* Until we fix all the decompressor's need to make sure
* data portion is linear.
*/
if (!pskb_may_pull(skb, skb->len))
goto err;
if (proto == PPP_COMP) { if (proto == PPP_COMP) {
ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN); ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
if (ns == 0) { if (ns == 0) {
...@@ -1603,7 +1618,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) ...@@ -1603,7 +1618,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
struct list_head *l; struct list_head *l;
int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
if (skb->len < mphdrlen + 1 || ppp->mrru == 0) if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
goto err; /* no good, throw it away */ goto err; /* no good, throw it away */
/* Decode sequence number and begin/end bits */ /* Decode sequence number and begin/end bits */
...@@ -2021,7 +2036,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) ...@@ -2021,7 +2036,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
unsigned char *dp = skb->data + 2; unsigned char *dp = skb->data + 2;
int len; int len;
if (skb->len < CCP_HDRLEN + 2 if (!pskb_may_pull(skb, CCP_HDRLEN + 2)
|| skb->len < (len = CCP_LENGTH(dp)) + 2) || skb->len < (len = CCP_LENGTH(dp)) + 2)
return; /* too short */ return; /* too short */
...@@ -2056,6 +2071,10 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) ...@@ -2056,6 +2071,10 @@ 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))
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))
......
...@@ -333,7 +333,11 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) ...@@ -333,7 +333,11 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
struct pppox_opt *relay_po = NULL; struct pppox_opt *relay_po = NULL;
if (sk->sk_state & PPPOX_BOUND) { if (sk->sk_state & PPPOX_BOUND) {
struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
int len = ntohs(ph->length);
skb_pull(skb, sizeof(struct pppoe_hdr)); skb_pull(skb, sizeof(struct pppoe_hdr));
skb_trim(skb, len);
ppp_input(&po->chan, skb); ppp_input(&po->chan, skb);
} else if (sk->sk_state & PPPOX_RELAY) { } else if (sk->sk_state & PPPOX_RELAY) {
relay_po = get_item_by_addr(&po->pppoe_relay); relay_po = get_item_by_addr(&po->pppoe_relay);
...@@ -371,17 +375,22 @@ static int pppoe_rcv(struct sk_buff *skb, ...@@ -371,17 +375,22 @@ static int pppoe_rcv(struct sk_buff *skb,
struct packet_type *pt) struct packet_type *pt)
{ {
struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw; struct pppoe_hdr *ph;
struct pppox_opt *po; struct pppox_opt *po;
struct sock *sk ; struct sock *sk;
int ret; int ret;
po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto drop;
if (!po) { if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
kfree_skb(skb); goto out;
return NET_RX_DROP;
} ph = (struct pppoe_hdr *) skb->nh.raw;
po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source);
if (!po)
goto drop;
sk = po->sk; sk = po->sk;
bh_lock_sock(sk); bh_lock_sock(sk);
...@@ -398,6 +407,10 @@ static int pppoe_rcv(struct sk_buff *skb, ...@@ -398,6 +407,10 @@ static int pppoe_rcv(struct sk_buff *skb,
sock_put(sk); sock_put(sk);
return ret; return ret;
drop:
kfree_skb(skb);
out:
return NET_RX_DROP;
} }
/************************************************************************ /************************************************************************
...@@ -411,9 +424,16 @@ static int pppoe_disc_rcv(struct sk_buff *skb, ...@@ -411,9 +424,16 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
struct packet_type *pt) struct packet_type *pt)
{ {
struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw; struct pppoe_hdr *ph;
struct pppox_opt *po; struct pppox_opt *po;
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto abort;
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
ph = (struct pppoe_hdr *) skb->nh.raw;
if (ph->code != PADT_CODE) if (ph->code != PADT_CODE)
goto abort; goto abort;
...@@ -441,17 +461,20 @@ static int pppoe_disc_rcv(struct sk_buff *skb, ...@@ -441,17 +461,20 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
abort: abort:
kfree_skb(skb); kfree_skb(skb);
out:
return NET_RX_SUCCESS; /* Lies... :-) */ return NET_RX_SUCCESS; /* Lies... :-) */
} }
static struct packet_type pppoes_ptype = { static struct packet_type pppoes_ptype = {
.type = __constant_htons(ETH_P_PPP_SES), .type = __constant_htons(ETH_P_PPP_SES),
.func = pppoe_rcv, .func = pppoe_rcv,
.data = (void *)1,
}; };
static struct packet_type pppoed_ptype = { static struct packet_type pppoed_ptype = {
.type = __constant_htons(ETH_P_PPP_DISC), .type = __constant_htons(ETH_P_PPP_DISC),
.func = pppoe_disc_rcv, .func = pppoe_disc_rcv,
.data = (void *)1,
}; };
/*********************************************************************** /***********************************************************************
......
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