Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ef62d8c authored by Ajay Agarwal's avatar Ajay Agarwal Committed by Gerrit - the friendly Code Review server
Browse files

usb: gadget: u_ether: Check tx_reqs before allocating new SKB



Commit fdafb970a9fc ("usb: gadget: u_ether: reorganize code for
better readability") refactored the eth_start_xmit function to
free old skb first, add RNDIS header to new SKB and then check
if disconnect interrupt has freed up the tx_reqs. If this
happens, then on next eth_start_xmit we will end up using the
previous skb which leads to page fault.
Fix this by first checking tx_reqs availability and then adding
RNDIS header.

Change-Id: I0bf59361c71c989a436685917301cabd62b91e95
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
Signed-off-by: default avatarSivasri Kumar Vanka <sivasri@codeaurora.org>
parent 00df9608
Loading
Loading
Loading
Loading
+24 −24
Original line number Diff line number Diff line
@@ -828,29 +828,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
	}

	dev->tx_pkts_rcvd++;
	/*
	 * no buffer copies needed, unless the network stack did it
	 * or the hardware can't use skb buffers.
	 * or there's not enough space for extra headers we need
	 */
	spin_lock_irqsave(&dev->lock, flags);
	if (dev->wrap && dev->port_usb)
		skb = dev->wrap(dev->port_usb, skb);
	spin_unlock_irqrestore(&dev->lock, flags);

	if (!skb) {
		if (dev->port_usb && dev->port_usb->supports_multi_frame) {
			/*
			 * Multi frame CDC protocols may store the frame for
			 * later which is not a dropped frame.
			 */
		} else {
			dev->net->stats.tx_dropped++;
		}

		/* no error code for dropped packets */
		return NETDEV_TX_OK;
	}

	/* Allocate memory for tx_reqs to support multi packet transfer */
	spin_lock_irqsave(&dev->req_lock, flags);
@@ -885,9 +862,30 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
		dev->tx_throttle++;
		netif_stop_queue(net);
	}
	spin_unlock_irqrestore(&dev->req_lock, flags);

	/* no buffer copies needed, unless the network stack did it
	 * or the hardware can't use skb buffers.
	 * or there's not enough space for extra headers we need
	 */
	spin_lock_irqsave(&dev->lock, flags);
	if (dev->wrap) {
		if (dev->port_usb)
			skb = dev->wrap(dev->port_usb, skb);
		if (!skb) {
			spin_unlock_irqrestore(&dev->lock, flags);
			/* Multi frame CDC protocols may store the frame for
			 * later which is not a dropped frame.
			 */
			if (dev->port_usb &&
					dev->port_usb->supports_multi_frame)
				goto multiframe;
			goto drop;
		}
	}

	dev->tx_skb_hold_count++;
	spin_unlock_irqrestore(&dev->req_lock, flags);
	spin_unlock_irqrestore(&dev->lock, flags);

	if (multi_pkt_xfer) {
		pr_debug("req->length:%d header_len:%u\n"
@@ -1010,7 +1008,9 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
			dev_kfree_skb_any(skb);
		else
			req->length = 0;
drop:
		dev->net->stats.tx_dropped++;
multiframe:
		spin_lock_irqsave(&dev->req_lock, flags);
		if (list_empty(&dev->tx_reqs))
			netif_start_queue(net);