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
This commit is contained in:
Selvaraj, Sridhar 2017-03-07 14:53:13 +05:30 committed by Sandeep Puligilla
parent 932f73b976
commit 046d77d673
3 changed files with 339 additions and 147 deletions

4
Kbuild
View File

@ -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

View File

@ -114,6 +114,10 @@
#include "wlan_pmo_ucfg_api.h"
#include "sir_api.h"
#ifdef CNSS_GENL
#include <net/cnss_nl.h>
#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;
}

View File

@ -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 <net/cnss_nl.h>
#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