usb: smd: Fix crash during reset when RmNet is connected

When a QMI/RMNET control connection is established, a diag
reset causes a crash due to a NULL pointer dereference. The
SMD channel pointer is set to NULL upon USB cable disconnect,
but a queued work function might still try to access that pointer.

Fix the crash by checking for NULL pointers in both smd_* and in
USB gadget transport functions that could pass a closed handle.

CRs-fixed: 336850
Change-Id: I87cb109f3e7007efe15b5acc81180151dd2ef023
Signed-off-by: Jack Pham <jackp@codeaurora.org>
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index e74b2e1..a5ceaff 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -209,6 +209,7 @@
 static void gsmd_rx_push(struct work_struct *w)
 {
 	struct gsmd_port *port = container_of(w, struct gsmd_port, push);
+	struct smd_port_info *pi = port->pi;
 	struct list_head *q;
 
 	pr_debug("%s: port:%p port#%d", __func__, port, port->port_num);
@@ -216,10 +217,9 @@
 	spin_lock_irq(&port->port_lock);
 
 	q = &port->read_queue;
-	while (!list_empty(q)) {
+	while (pi->ch && !list_empty(q)) {
 		struct usb_request *req;
 		int avail;
-		struct smd_port_info *pi = port->pi;
 
 		req = list_first_entry(q, struct usb_request, list);
 
@@ -296,21 +296,24 @@
 {
 	struct gsmd_port *port = container_of(w, struct gsmd_port, pull);
 	struct list_head *pool = &port->write_pool;
+	struct smd_port_info *pi = port->pi;
+	struct usb_ep *in;
 
 	pr_debug("%s: port:%p port#%d pool:%p\n", __func__,
 			port, port->port_num, pool);
 
+	spin_lock_irq(&port->port_lock);
+
 	if (!port->port_usb) {
 		pr_debug("%s: usb is disconnected\n", __func__);
+		spin_unlock_irq(&port->port_lock);
 		gsmd_read_pending(port);
 		return;
 	}
 
-	spin_lock_irq(&port->port_lock);
-	while (!list_empty(pool)) {
+	in = port->port_usb->in;
+	while (pi->ch && !list_empty(pool)) {
 		struct usb_request *req;
-		struct usb_ep *in = port->port_usb->in;
-		struct smd_port_info *pi = port->pi;
 		int avail;
 		int ret;