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

Commit fcd0515d authored by Ajay Agarwal's avatar Ajay Agarwal
Browse files

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



Commit fdafb970 ("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>
parent 4aaa9c35
Loading
Loading
Loading
Loading
+24 −24
Original line number Original line Diff line number Diff line
@@ -818,29 +818,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
	}
	}


	dev->tx_pkts_rcvd++;
	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 */
	/* Allocate memory for tx_reqs to support multi packet transfer */
	spin_lock_irqsave(&dev->req_lock, flags);
	spin_lock_irqsave(&dev->req_lock, flags);
@@ -875,9 +852,30 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
		dev->tx_throttle++;
		dev->tx_throttle++;
		netif_stop_queue(net);
		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++;
	dev->tx_skb_hold_count++;
	spin_unlock_irqrestore(&dev->req_lock, flags);
	spin_unlock_irqrestore(&dev->lock, flags);


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