From 046d77d67356cfadf8cfa571af570646a117f5c4 Mon Sep 17 00:00:00 2001 From: "Selvaraj, Sridhar" Date: Tue, 7 Mar 2017 14:53:13 +0530 Subject: [PATCH] qcacld-3.0: Add support to use generic netlink sockets for userspace apps Currently user space communication functions[cnss diag, PTT socket app] in host driver uses netlink user sockets which is a security concern from Linux Android SE policies. Add support for to use netlink family cld80211 which uses generic netlink sockets. Change-Id: I4ea49ac6d7c9381212c93567fdc40f90e04dfba4 CRs-Fixed: 1112784 --- Kbuild | 4 + core/hdd/src/wlan_hdd_main.c | 24 +- core/hdd/src/wlan_hdd_oemdata.c | 458 ++++++++++++++++++++++---------- 3 files changed, 339 insertions(+), 147 deletions(-) diff --git a/Kbuild b/Kbuild index 3ce4903fc3bf..65294538fbf7 100644 --- a/Kbuild +++ b/Kbuild @@ -1507,6 +1507,10 @@ ifeq ($(CONFIG_QCACLD_WLAN_LFR3),y) CDEFINES += -DWLAN_FEATURE_ROAM_OFFLOAD endif +ifeq ($(CONFIG_CNSS_GENL), y) +CDEFINES += -DCNSS_GENL +endif + ifeq ($(CONFIG_QCACLD_WLAN_LFR2),y) CDEFINES += -DWLAN_FEATURE_HOST_ROAM endif diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index a1351a17a5f4..d225addb368f 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -114,6 +114,10 @@ #include "wlan_pmo_ucfg_api.h" #include "sir_api.h" +#ifdef CNSS_GENL +#include +#endif + #ifdef MODULE #define WLAN_MODULE_NAME module_name(THIS_MODULE) #else @@ -9270,6 +9274,24 @@ void wlan_hdd_enable_roaming(hdd_adapter_t *adapter) } } +/** + * nl_srv_bcast_svc() - Wrapper function to send bcast msgs to SVC mcast group + * @skb: sk buffer pointer + * + * Sends the bcast message to SVC multicast group with generic nl socket + * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send. + * + * Return: None + */ +static void nl_srv_bcast_svc(struct sk_buff *skb) +{ +#ifdef CNSS_GENL + nl_srv_bcast(skb, CLD80211_MCGRP_SVC_MSGS, WLAN_NL_MSG_SVC); +#else + nl_srv_bcast(skb); +#endif +} + void wlan_hdd_send_svc_nlink_msg(int radio, int type, void *data, int len) { struct sk_buff *skb; @@ -9354,7 +9376,7 @@ void wlan_hdd_send_svc_nlink_msg(int radio, int type, void *data, int len) nlh->nlmsg_len += tlv_len; skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + len + tlv_len)); - nl_srv_bcast(skb); + nl_srv_bcast_svc(skb); return; } diff --git a/core/hdd/src/wlan_hdd_oemdata.c b/core/hdd/src/wlan_hdd_oemdata.c index 1f9e6392ec01..01799882c9a8 100644 --- a/core/hdd/src/wlan_hdd_oemdata.c +++ b/core/hdd/src/wlan_hdd_oemdata.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -46,6 +46,10 @@ #include "wma.h" #include "sme_api.h" +#ifdef CNSS_GENL +#include +#endif + static struct hdd_context_s *p_hdd_ctx; /** @@ -162,6 +166,27 @@ int iw_get_oem_data_cap(struct net_device *dev, return 0; } +/** + * nl_srv_ucast_oem() - Wrapper function to send ucast msgs to OEM + * @skb: sk buffer pointer + * @dst_pid: Destination PID + * @flag: flags + * + * Sends the ucast message to OEM with generic nl socket if CNSS_GENL + * is enabled. Else, use the legacy netlink socket to send. + * + * Return: None + */ +static void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag) +{ +#ifdef CNSS_GENL + nl_srv_ucast(skb, dst_pid, flag, WLAN_NL_MSG_OEM, + CLD80211_MCGRP_OEM_MSGS); +#else + nl_srv_ucast(skb, dst_pid, flag); +#endif +} + /** * send_oem_reg_rsp_nlink_msg() - send oem registration response * @@ -240,7 +265,7 @@ static void send_oem_reg_rsp_nlink_msg(void) hdd_notice("sending App Reg Response length (%d) to process pid (%d)", aniHdr->length, p_hdd_ctx->oem_pid); - (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); return; } @@ -285,7 +310,7 @@ static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code) hdd_notice("sending oem error response to process pid (%d)", app_pid); - (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT); + (void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT); return; } @@ -344,7 +369,7 @@ void hdd_send_oem_data_rsp_msg(struct oem_data_rsp *oem_data_rsp) hdd_notice("sending Oem Data Response of len (%d) to process pid (%d)", oem_data_rsp->rsp_len, p_hdd_ctx->oem_pid); - (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); return; } @@ -543,7 +568,7 @@ static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList) hdd_notice("sending channel info resp for num channels (%d) to pid (%d)", numOfChannels, p_hdd_ctx->oem_pid); - (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); return 0; } @@ -604,7 +629,7 @@ static int oem_process_set_cap_req_msg(int oem_cap_len, hdd_info("sending oem response to process pid %d", app_pid); - (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT); + (void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT); return error_code; } @@ -670,7 +695,7 @@ static int oem_process_get_cap_req_msg(void) hdd_info("send rsp to oem-pid:%d for get_capability", p_hdd_ctx->oem_pid); - (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); return 0; } @@ -781,11 +806,288 @@ void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac, pPeerInfo->peer_chan_info.reg_info_1, pPeerInfo->peer_chan_info.reg_info_2); - (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); return; } +/** + * oem_app_reg_req_handler() - function to handle APP registration request + * from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_app_reg_req_handler(struct hdd_context_s *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + char *sign_str = NULL; + + /* Registration request is only allowed for Qualcomm Application */ + hdd_info("Received App Reg Req from App process pid(%d), len(%d)", + pid, msg_hdr->length); + + sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)); + if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) && + (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR, + OEM_APP_SIGNATURE_LEN))) { + hdd_info("Valid App Reg Req from oem app process pid(%d)", pid); + + hdd_ctx->oem_app_registered = true; + hdd_ctx->oem_pid = pid; + send_oem_reg_rsp_nlink_msg(); + } else { + hdd_err("Invalid signature in App Reg Req from pid(%d)", pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_SIGNATURE); + return -EPERM; + } + + return 0; +} + +/** + * oem_data_req_handler() - function to handle data_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_data_req_handler(struct hdd_context_s *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_info("Received Oem Data Request length(%d) from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hdd_err("OEM DataReq: app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) { + hdd_err("Invalid length (%d) in Oem Data Request", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + oem_process_data_req_msg(msg_hdr->length, + (char *) ((char *)msg_hdr + + sizeof(tAniMsgHdr))); + + return 0; +} + +/** + * oem_chan_info_req_handler() - function to handle chan_info_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_chan_info_req_handler(struct hdd_context_s *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_info("Received channel info request, num channel(%d) from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hdd_err("Chan InfoReq: app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + /* message length contains list of channel ids */ + if ((!msg_hdr->length) || + (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) { + hdd_err("Invalid length (%d) in channel info request", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + oem_process_channel_info_req_msg(msg_hdr->length, + (char *)((char *)msg_hdr + sizeof(tAniMsgHdr))); + + return 0; +} + +/** + * oem_set_cap_req_handler() - function to handle set_cap_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_set_cap_req_handler(struct hdd_context_s *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_info("Received set oem cap req of length:%d from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* oem app is not registered yet or pid is different */ + hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || + (sizeof(struct sme_oem_capability) < msg_hdr->length)) { + hdd_err("Invalid length (%d) in set_oem_capability", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + oem_process_set_cap_req_msg(msg_hdr->length, (char *) + ((char *)msg_hdr + sizeof(tAniMsgHdr)), + pid); + return 0; +} + +/** + * oem_get_cap_req_handler() - function to handle get_cap_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_get_cap_req_handler(struct hdd_context_s *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_info("Rcvd get oem capability req - length:%d from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* oem app is not registered yet or pid is different */ + hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + oem_process_get_cap_req_msg(); + return 0; +} + +/** + * oem_request_dispatcher() - OEM command dispatcher API + * @msg_hdr: ANI Message Header + * @pid: process id + * + * This API is used to dispatch the command from OEM depending + * on the type of the message received. + * + * Return: None + */ +static void oem_request_dispatcher(tAniMsgHdr *msg_hdr, int pid) +{ + switch (msg_hdr->type) { + case ANI_MSG_APP_REG_REQ: + oem_app_reg_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_OEM_DATA_REQ: + oem_data_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_CHANNEL_INFO_REQ: + oem_chan_info_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_SET_OEM_CAP_REQ: + oem_set_cap_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_GET_OEM_CAP_REQ: + oem_get_cap_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + default: + hdd_err("Received Invalid message type (%d), length (%d)", + msg_hdr->type, msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_TYPE); + } +} + +#ifdef CNSS_GENL +/** + * oem_cmd_handler() - API to handle OEM commands + * @data: Pointer to data + * @data_len: length of the received data + * @ctx: Pointer to the context + * @pid: Process id + * + * This API handles the command from OEM application from user space and + * send back event to user space if necessary. + * + * Return: None + */ +static void oem_cmd_handler(const void *data, int data_len, void *ctx, int pid) +{ + tAniMsgHdr *msg_hdr; + int ret; + struct nlattr *tb[CLD80211_ATTR_MAX + 1]; + + ret = wlan_hdd_validate_context(p_hdd_ctx); + if (ret) { + hdd_err("hdd ctx validate fails"); + return; + } + + if (nla_parse(tb, CLD80211_ATTR_MAX, data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return; + } + + if (!tb[CLD80211_ATTR_DATA]) { + hdd_err("attr ATTR_DATA failed"); + return; + } + + msg_hdr = (tAniMsgHdr *)nla_data(tb[CLD80211_ATTR_DATA]); + if (!msg_hdr) { + hdd_err("msg_hdr null"); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_NULL_MESSAGE_HEADER); + return; + } + oem_request_dispatcher(msg_hdr, pid); + + return; +} + +/** + * oem_activate_service() - API to register the oem command handler + * @hdd_ctx: Pointer to HDD Context + * + * This API is used to register the oem app command handler. Argument + * @pAdapter is given for prototype compatibility with legacy code. + * + * Return: 0 + */ +int oem_activate_service(struct hdd_context_s *hdd_ctx) +{ + p_hdd_ctx = hdd_ctx; + register_cld_cmd_cb(WLAN_NL_MSG_OEM, oem_cmd_handler, NULL); + return 0; +} +#else + /* * Callback function invoked by Netlink service for all netlink * messages (from user space) addressed to WLAN_NL_MSG_OEM @@ -806,7 +1108,6 @@ static int oem_msg_callback(struct sk_buff *skb) struct nlmsghdr *nlh; tAniMsgHdr *msg_hdr; int ret; - char *sign_str = NULL; nlh = (struct nlmsghdr *)skb->data; if (!nlh) { @@ -836,142 +1137,7 @@ static int oem_msg_callback(struct sk_buff *skb) return -EPERM; } - switch (msg_hdr->type) { - case ANI_MSG_APP_REG_REQ: - /* Registration request is only allowed for Qualcomm Application */ - hdd_notice("Received App Req Req from App process pid(%d), len(%d)", - nlh->nlmsg_pid, msg_hdr->length); - - sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)); - if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) && - (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR, - OEM_APP_SIGNATURE_LEN))) { - hdd_notice("Valid App Req Req from oem app process pid(%d)", - nlh->nlmsg_pid); - - p_hdd_ctx->oem_app_registered = true; - p_hdd_ctx->oem_pid = nlh->nlmsg_pid; - send_oem_reg_rsp_nlink_msg(); - } else { - hdd_err("Invalid signature in App Reg Request from pid(%d)", - nlh->nlmsg_pid); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_INVALID_SIGNATURE); - return -EPERM; - } - break; - - case ANI_MSG_OEM_DATA_REQ: - hdd_notice("Received Oem Data Request length(%d) from pid: %d", - msg_hdr->length, nlh->nlmsg_pid); - - if ((!p_hdd_ctx->oem_app_registered) || - (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { - /* either oem app is not registered yet or pid is different */ - hdd_err("OEM DataReq: app not registered(%d) or incorrect pid(%d)", - p_hdd_ctx->oem_app_registered, - nlh->nlmsg_pid); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_APP_NOT_REGISTERED); - return -EPERM; - } - - if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) { - hdd_err("Invalid length (%d) in Oem Data Request", - msg_hdr->length); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_INVALID_MESSAGE_LENGTH); - return -EPERM; - } - oem_process_data_req_msg(msg_hdr->length, - (char *)((char *)msg_hdr + - sizeof(tAniMsgHdr))); - break; - - case ANI_MSG_CHANNEL_INFO_REQ: - hdd_notice("Received channel info request, num channel(%d) from pid: %d", - msg_hdr->length, nlh->nlmsg_pid); - - if ((!p_hdd_ctx->oem_app_registered) || - (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { - /* either oem app is not registered yet or pid is different */ - hdd_err("Chan InfoReq: app not registered(%d) or incorrect pid(%d)", - p_hdd_ctx->oem_app_registered, - nlh->nlmsg_pid); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_APP_NOT_REGISTERED); - return -EPERM; - } - - /* message length contains list of channel ids */ - if ((!msg_hdr->length) || - (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) { - hdd_err("Invalid length (%d) in channel info request", - msg_hdr->length); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_INVALID_MESSAGE_LENGTH); - return -EPERM; - } - oem_process_channel_info_req_msg(msg_hdr->length, - (char *)((char *)msg_hdr + - sizeof(tAniMsgHdr))); - break; - - case ANI_MSG_SET_OEM_CAP_REQ: - hdd_info("Received set oem capability req of length:%d from pid: %d", - msg_hdr->length, nlh->nlmsg_pid); - - if ((!p_hdd_ctx->oem_app_registered) || - (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { - /* oem app is not registered yet or pid is different */ - hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)", - p_hdd_ctx->oem_app_registered, - nlh->nlmsg_pid); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_APP_NOT_REGISTERED); - return -EPERM; - } - - if ((!msg_hdr->length) || - (sizeof(struct sme_oem_capability) < msg_hdr->length)) { - hdd_err("Invalid length (%d) in set_oem_capability", - msg_hdr->length); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_INVALID_MESSAGE_LENGTH); - return -EPERM; - } - - oem_process_set_cap_req_msg(msg_hdr->length, - (char *)((char *)msg_hdr + - sizeof(tAniMsgHdr)), - nlh->nlmsg_pid); - break; - - case ANI_MSG_GET_OEM_CAP_REQ: - hdd_info("Rcvd get oem capability req of length:%d from pid: %d", - msg_hdr->length, nlh->nlmsg_pid); - - if ((!p_hdd_ctx->oem_app_registered) || - (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { - /* oem app is not registered yet or pid is different */ - hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)", - p_hdd_ctx->oem_app_registered, - nlh->nlmsg_pid); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_APP_NOT_REGISTERED); - return -EPERM; - } - - oem_process_get_cap_req_msg(); - break; - - default: - hdd_err("Received Invalid message type (%d), length (%d)", - msg_hdr->type, msg_hdr->length); - send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, - OEM_ERR_INVALID_MESSAGE_TYPE); - return -EPERM; - } + oem_request_dispatcher(msg_hdr, nlh->nlmsg_pid); return 0; } @@ -1003,5 +1169,5 @@ int oem_activate_service(struct hdd_context_s *hdd_ctx) /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback); } - +#endif #endif