u_ether: Handle memory allocation failure case on tx path

With multipacket feature enabled, if the memory allocation for
tx request buffer fails, accessing the req->buf leads to null
pointer dereference.

Hence, handle memory alloction failure case and return -ENOMEM.

Change-Id: Ic5faac8ea7eb056755b03007c48ff085f10afa20
Signed-off-by: Rajkumar Raghupathy <raghup@codeaurora.org>
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 41050af..4dbeba1 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -613,7 +613,7 @@
 	return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
 }
 
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
 {
 	struct list_head	*act;
 	struct usb_request	*req;
@@ -630,7 +630,21 @@
 		if (!req->buf)
 			req->buf = kmalloc(dev->tx_req_bufsize,
 						GFP_ATOMIC);
+
+		if (!req->buf)
+			goto free_buf;
 	}
+	return 0;
+
+free_buf:
+	/* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+	dev->tx_req_bufsize = 0;
+	list_for_each(act, &dev->tx_reqs) {
+		req = container_of(act, struct usb_request, list);
+		kfree(req->buf);
+		req->buf = NULL;
+	}
+	return -ENOMEM;
 }
 
 static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -662,8 +676,11 @@
 	}
 
 	/* Allocate memory for tx_reqs to support multi packet transfer */
-	if (multi_pkt_xfer && !dev->tx_req_bufsize)
-		alloc_tx_buffer(dev);
+	if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+		retval = alloc_tx_buffer(dev);
+		if (retval < 0)
+			return -ENOMEM;
+	}
 
 	/* apply outgoing CDC or RNDIS filters */
 	if (skb && !is_promisc(cdc_filter)) {
@@ -1534,8 +1551,10 @@
 			list_del(&req->list);
 
 			spin_unlock(&dev->req_lock);
-			if (link->multi_pkt_xfer)
+			if (link->multi_pkt_xfer) {
 				kfree(req->buf);
+				req->buf = NULL;
+			}
 			usb_ep_free_request(link->in_ep, req);
 			spin_lock(&dev->req_lock);
 		}