diff options
| author | Atish Kumar Patra <apatra@codeaurora.org> | 2015-04-24 18:16:28 -0600 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:13:50 -0700 |
| commit | 6b3fc777e59ad3ac76d4dd89ac251f7004100b79 (patch) | |
| tree | 0a0594455a61615fdef86c2d31411b8d90612a8d | |
| parent | f359b9f372b0fbfb0000618750bf0dff8408ecba (diff) | |
net: ipc_router: Add support for IPC Router version negotiation
Currently, IPC Router statically associates the version of the
protocol to be used with each link. Thus, dynamic version negotiation
is not possible.
Add support for version negotiation that sets IPC Router version
after a successful negotiation.
Change-Id: Iea04742ef30443c1e36760561e7f20175c4fbaa6
Signed-off-by: Atish Kumar Patra <apatra@codeaurora.org>
| -rw-r--r-- | include/linux/ipc_router.h | 4 | ||||
| -rw-r--r-- | net/ipc_router/ipc_router_core.c | 71 | ||||
| -rw-r--r-- | net/ipc_router/ipc_router_private.h | 3 |
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 |
