--- clip.c.orig Wed Oct 17 10:39:30 2001 +++ clip.c Wed Oct 17 10:51:46 2001 @@ -431,28 +431,22 @@ ATM_SKB(skb)->atm_options = vcc->atm_options; entry->vccs->last_use = jiffies; DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev); + spin_lock_irqsave(&clip_priv->xoff_lock,flags); old = xchg(&entry->vccs->xoff,1); /* assume XOFF ... */ if (old) { + spin_unlock_irqrestore(&clip_priv->xoff_lock,flags); printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n"); return 0; } + if (atm_may_send(vcc,0)) + entry->vccs->xoff = 0; + else + netif_stop_queue(dev); /* XOFF -> throttle immediately */ + spin_unlock_irqrestore(&clip_priv->xoff_lock,flags); + clip_priv->stats.tx_packets++; clip_priv->stats.tx_bytes += skb->len; (void) vcc->send(vcc,skb); - if (atm_may_send(vcc,0)) { - entry->vccs->xoff = 0; - return 0; - } - spin_lock_irqsave(&clip_priv->xoff_lock,flags); - netif_stop_queue(dev); /* XOFF -> throttle immediately */ - barrier(); - if (!entry->vccs->xoff) - netif_start_queue(dev); - /* Oh, we just raced with clip_pop. netif_start_queue should be - good enough, because nothing should really be asleep because - of the brief netif_stop_queue. If this isn't true or if it - changes, use netif_wake_queue instead. */ - spin_unlock_irqrestore(&clip_priv->xoff_lock,flags); return 0; } --- clip.c.orig Thu Nov 1 15:58:37 2001 +++ clip.c Thu Nov 1 16:10:53 2001 @@ -422,6 +422,29 @@ if (entry->vccs->encap) { void *here; + /* Mitchell Blank's patch to fix ping over IPSEC problems. */ + /* "The bug is that clip_start_xmit does a skb_push without verifying that + there is sufficient space in the skb's headroom for the 1483 encapsulation. + Normally this isn't a problem since all skb's are born with 16 bytes of + headroom (under "normal" circumstances ethernet uses 14 and 2 are wasted + for alignment - since we don't need an ethernet header we usually will have + plenty of space) but in this case IPSec has already taken most of the + headroom so we need to make more before tacking on our own header." */ + + if (skb_headroom(skb) < RFC1483LLC_LEN || skb_cloned(skb) || skb_shared(skb)) { + struct sk_buff *skb2 = skb_realloc_headroom(skb,RFC1483LLC_LEN); + if (!skb2) { + clip_priv->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + /* Not sure about these next two lines, actually... */ + if (skb->sk) skb_set_owner_w(skb2, skb->sk); + dev_kfree_skb(skb); + skb = skb2; + } + /* End Patch */ + here = skb_push(skb,RFC1483LLC_LEN); memcpy(here,llc_oui,sizeof(llc_oui)); ((u16 *) here)[3] = skb->protocol;