msm: ipc: Allow QMI clients to send messages after IRSC is complete

Currently there exists a small time interval during initialization
where QMI clients in user-space can communicate with QMI services
before the IPC Router Security Configuration(IRSC) is complete.

Only allow clients to communicate after IRSC is complete.

Change-Id: I773ad5b3cb02c51a725cd60a77466876c1498b64
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index ca07ae0..a2da3a5 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -194,12 +194,6 @@
 static struct workqueue_struct *msm_ipc_router_workqueue;
 
 enum {
-	CLIENT_PORT,
-	SERVER_PORT,
-	CONTROL_PORT,
-};
-
-enum {
 	DOWN,
 	UP,
 };
@@ -2160,6 +2154,11 @@
 		mutex_lock(&control_ports_lock);
 		list_del(&port_ptr->list);
 		mutex_unlock(&control_ports_lock);
+	} else if (port_ptr->type == IRSC_PORT) {
+		mutex_lock(&local_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&local_ports_lock);
+		signal_irsc_completion();
 	}
 
 	mutex_lock(&port_ptr->port_rx_q_lock);
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 179e3de..d56c0dd 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -66,6 +66,13 @@
 	MSM_IPC_ROUTER_WRITE_DONE,
 };
 
+enum {
+	CLIENT_PORT,
+	SERVER_PORT,
+	CONTROL_PORT,
+	IRSC_PORT,
+};
+
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 64b3db4..58a492e 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -280,6 +280,9 @@
 		goto out_sendmsg;
 	}
 
+	if (port_ptr->type == CLIENT_PORT)
+		wait_for_irsc_completion();
+
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
 	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
 		ret = total_len;
@@ -429,6 +432,8 @@
 
 	case IPC_ROUTER_IOCTL_CONFIG_SEC_RULES:
 		ret = msm_ipc_config_sec_rules((void *)arg);
+		if (ret != -EPERM)
+			port_ptr->type = IRSC_PORT;
 		break;
 
 	default:
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
index 7b2298e..756e24e 100644
--- a/arch/arm/mach-msm/msm_ipc_router_security.c
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -29,6 +29,7 @@
 #include "ipc_router.h"
 #include "msm_ipc_router_security.h"
 
+#define IRSC_COMPLETION_TIMEOUT_MS 30000
 #define SEC_RULES_HASH_SZ 32
 struct security_rule {
 	struct list_head list;
@@ -41,6 +42,31 @@
 
 static DEFINE_MUTEX(security_rules_lock);
 static struct list_head security_rules[SEC_RULES_HASH_SZ];
+static DECLARE_COMPLETION(irsc_completion);
+
+/**
+ * wait_for_irsc_completion() - Wait for IPC Router Security Configuration
+ *                              (IRSC) to complete
+ */
+void wait_for_irsc_completion(void)
+{
+	unsigned long rem_jiffies;
+	do {
+		rem_jiffies = wait_for_completion_timeout(&irsc_completion,
+				msecs_to_jiffies(IRSC_COMPLETION_TIMEOUT_MS));
+		if (rem_jiffies)
+			return;
+		pr_err("%s: waiting for IPC Security Conf.\n", __func__);
+	} while (1);
+}
+
+/**
+ * signal_irsc_completion() - Signal the completion of IRSC
+ */
+void signal_irsc_completion(void)
+{
+	complete_all(&irsc_completion);
+}
 
 /**
  * check_permisions() - Check whether the process has permissions to
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.h b/arch/arm/mach-msm/msm_ipc_router_security.h
index d6283db..9cc61e9 100644
--- a/arch/arm/mach-msm/msm_ipc_router_security.h
+++ b/arch/arm/mach-msm/msm_ipc_router_security.h
@@ -73,6 +73,17 @@
  */
 int msm_ipc_router_security_init(void);
 
+/**
+ * wait_for_irsc_completion() - Wait for IPC Router Security Configuration
+ *                              (IRSC) to complete
+ */
+void wait_for_irsc_completion(void);
+
+/**
+ * signal_irsc_completion() - Signal the completion of IRSC
+ */
+void signal_irsc_completion(void);
+
 #else
 
 static inline int check_permissions(void)
@@ -100,5 +111,10 @@
 {
 	return 0;
 }
+
+static inline void wait_for_irsc_completion(void) { }
+
+static inline void signal_irsc_completion(void) { }
+
 #endif
 #endif