diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 6da52d12df68..5214786e61d1 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -292,10 +292,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) struct atm_vcc *vcc; int ret; + if (!pskb_may_pull(skb, 1)) { + kfree_skb(skb); + return DROP_PACKET; + } + ATM_SKB(skb)->vcc = pvcc->atmvcc; pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); - if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) - (void) skb_pull(skb, 1); vcc = ATM_SKB(skb)->vcc; bh_lock_sock(sk_atm(vcc)); @@ -317,23 +320,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) switch (pvcc->encaps) { /* LLC encapsulation needed */ case e_llc: - if (skb_headroom(skb) < LLC_LEN) { - struct sk_buff *n; - n = skb_realloc_headroom(skb, LLC_LEN); - if (n != NULL && - !pppoatm_may_send(pvcc, n->truesize)) { - kfree_skb(n); - goto nospace; - } - consume_skb(skb); - skb = n; - if (skb == NULL) { - bh_unlock_sock(sk_atm(vcc)); - return DROP_PACKET; - } - } else if (!pppoatm_may_send(pvcc, skb->truesize)) + if (skb_cow_head(skb, LLC_LEN)) { + bh_unlock_sock(sk_atm(vcc)); + kfree_skb(skb); + return DROP_PACKET; + } + if (!pppoatm_may_send(pvcc, skb->truesize)) goto nospace; - memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); break; case e_vc: if (!pppoatm_may_send(pvcc, skb->truesize)) @@ -346,6 +339,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) return 1; } + if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) + skb_pull(skb, 1); + + if (pvcc->encaps == e_llc) + memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); + atm_account_tx(vcc, skb); pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); @@ -355,13 +354,6 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) return ret; nospace: bh_unlock_sock(sk_atm(vcc)); - /* - * We don't have space to send this SKB now, but we might have - * already applied SC_COMP_PROT compression, so may need to undo - */ - if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 && - skb->data[-1] == '\0') - (void) skb_push(skb, 1); return 0; }