summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/ipc_router.h4
-rw-r--r--net/ipc_router/ipc_router_core.c71
-rw-r--r--net/ipc_router/ipc_router_private.h3
3 files changed, 75 insertions, 3 deletions
diff --git a/include/linux/ipc_router.h b/include/linux/ipc_router.h
index c89b972a91bd..ad2192d89e0d 100644
--- a/include/linux/ipc_router.h
+++ b/include/linux/ipc_router.h
@@ -53,8 +53,10 @@ union rr_control_msg {
uint32_t cmd;
struct {
uint32_t cmd;
- uint32_t magic;
+ uint32_t checksum;
+ uint32_t versions;
uint32_t capability;
+ uint32_t reserved;
} hello;
struct {
uint32_t cmd;
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index 2e884aa9fb8c..99486e9ac703 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -217,6 +217,40 @@ static void init_routing_table(void)
}
/**
+ * ipc_router_calc_checksum() - compute the checksum for extended HELLO message
+ * @msg: Reference to the IPC Router HELLO message.
+ *
+ * Return: Computed checksum value, 0 if msg is NULL.
+ */
+static uint32_t ipc_router_calc_checksum(union rr_control_msg *msg)
+{
+ uint32_t checksum = 0;
+ int i, len;
+ uint16_t upper_nb;
+ uint16_t lower_nb;
+ void *hello;
+
+ if (!msg)
+ return checksum;
+ hello = msg;
+ len = sizeof(*msg);
+
+ for (i = 0; i < len/IPCR_WORD_SIZE; i++) {
+ lower_nb = (*((uint32_t *)hello)) & IPC_ROUTER_CHECKSUM_MASK;
+ upper_nb = ((*((uint32_t *)hello)) >> 16) &
+ IPC_ROUTER_CHECKSUM_MASK;
+ checksum = checksum + upper_nb + lower_nb;
+ hello = ((uint32_t *)hello) + 1;
+ }
+ while (checksum > 0xFFFF)
+ checksum = (checksum & IPC_ROUTER_CHECKSUM_MASK) +
+ ((checksum >> 16) & IPC_ROUTER_CHECKSUM_MASK);
+
+ checksum = ~checksum & IPC_ROUTER_CHECKSUM_MASK;
+ return checksum;
+}
+
+/**
* skb_copy_to_log_buf() - copies the required number bytes from the skb_queue
* @skb_head: skb_queue head that contains the data.
* @pl_len: length of payload need to be copied.
@@ -2379,8 +2413,37 @@ int ipc_router_set_conn(struct msm_ipc_port *port_ptr,
return 0;
}
+/**
+ * do_version_negotiation() - perform a version negotiation and set the version
+ * @xprt_info: Pointer to the IPC Router transport info structure.
+ * @msg: Pointer to the IPC Router HELLO message.
+ *
+ * This function performs the version negotiation by verifying the computed
+ * checksum first. If the checksum matches with the magic number, it sets the
+ * negotiated IPC Router version in transport.
+ */
+static void do_version_negotiation(struct msm_ipc_router_xprt_info *xprt_info,
+ union rr_control_msg *msg)
+{
+ uint32_t magic;
+ unsigned version;
+
+ if (!xprt_info)
+ return;
+ magic = ipc_router_calc_checksum(msg);
+ if (magic == IPC_ROUTER_HELLO_MAGIC) {
+ version = fls(msg->hello.versions & IPC_ROUTER_VER_BITMASK) - 1;
+ /*Bit 0 & 31 are reserved for future usage*/
+ if ((version > 0) &&
+ (version != (sizeof(version) * BITS_PER_BYTE - 1)) &&
+ xprt_info->xprt->set_version)
+ xprt_info->xprt->set_version(xprt_info->xprt, version);
+ }
+}
+
static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
- struct rr_header_v1 *hdr)
+ union rr_control_msg *msg,
+ struct rr_header_v1 *hdr)
{
int i, rc = 0;
union rr_control_msg ctl;
@@ -2397,9 +2460,13 @@ static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
}
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
+ do_version_negotiation(xprt_info, msg);
/* Send a reply HELLO message */
memset(&ctl, 0, sizeof(ctl));
ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+ ctl.hello.checksum = IPC_ROUTER_HELLO_MAGIC;
+ ctl.hello.versions = (uint32_t)IPC_ROUTER_VER_BITMASK;
+ ctl.hello.checksum = ipc_router_calc_checksum(&ctl);
rc = ipc_router_send_ctl_msg(xprt_info, &ctl,
IPC_ROUTER_DUMMY_DEST_NODE);
if (rc < 0) {
@@ -2599,7 +2666,7 @@ static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
switch (msg->cmd) {
case IPC_ROUTER_CTRL_CMD_HELLO:
- rc = process_hello_msg(xprt_info, hdr);
+ rc = process_hello_msg(xprt_info, msg, hdr);
break;
case IPC_ROUTER_CTRL_CMD_RESUME_TX:
rc = process_resume_tx_msg(msg, pkt);
diff --git a/net/ipc_router/ipc_router_private.h b/net/ipc_router/ipc_router_private.h
index 465bf4149f1b..2dc0a0ff5fdb 100644
--- a/net/ipc_router/ipc_router_private.h
+++ b/net/ipc_router/ipc_router_private.h
@@ -32,6 +32,9 @@
* with an existing alternate transport in user-space, if needed.
*/
#define IPC_ROUTER_V2 3
+#define IPC_ROUTER_VER_BITMASK ((BIT(IPC_ROUTER_V1)) | (BIT(IPC_ROUTER_V2)))
+#define IPC_ROUTER_HELLO_MAGIC 0xE110
+#define IPC_ROUTER_CHECKSUM_MASK 0xFFFF
#define IPC_ROUTER_ADDRESS 0x0000FFFF