|
@@ -199,6 +199,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
|
|
|
struct brcmf_if *ifp = netdev_priv(ndev);
|
|
|
struct brcmf_pub *drvr = ifp->drvr;
|
|
|
struct ethhdr *eh;
|
|
|
+ int head_delta;
|
|
|
|
|
|
brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
|
|
|
|
|
@@ -211,13 +212,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
|
- /* Make sure there's enough writable headroom*/
|
|
|
- ret = skb_cow_head(skb, drvr->hdrlen);
|
|
|
- if (ret < 0) {
|
|
|
- brcmf_err("%s: skb_cow_head failed\n",
|
|
|
- brcmf_ifname(ifp));
|
|
|
- dev_kfree_skb(skb);
|
|
|
- goto done;
|
|
|
+ /* Make sure there's enough writeable headroom */
|
|
|
+ if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
|
|
|
+ head_delta = drvr->hdrlen - skb_headroom(skb);
|
|
|
+
|
|
|
+ brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n",
|
|
|
+ brcmf_ifname(ifp), head_delta);
|
|
|
+ atomic_inc(&drvr->bus_if->stats.pktcowed);
|
|
|
+ ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0,
|
|
|
+ GFP_ATOMIC);
|
|
|
+ if (ret < 0) {
|
|
|
+ brcmf_err("%s: failed to expand headroom\n",
|
|
|
+ brcmf_ifname(ifp));
|
|
|
+ atomic_inc(&drvr->bus_if->stats.pktcow_failed);
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* validate length for ether packet */
|