msm: ipa: support ipacm cleanup

Support header/filter, routing rules
cleanup when user-space module
crashed like ipacm and also cached
the wlan client connect messages
for ipacm to query.

Change-Id: Ib09cbe0e9114aa5a5673898ff796de7e7944af35
Acked-by: Pooja Kumari <kumarip@qti.qualcomm.com>
Signed-off-by: Mohammed Javid <mjavid@codeaurora.org>
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
This commit is contained in:
Skylar Chang 2018-04-07 16:42:36 -07:00 committed by Gerrit - the friendly Code Review server
parent eea1a62727
commit aef2c9f15c
22 changed files with 1329 additions and 477 deletions

View file

@ -340,13 +340,13 @@ int ipa_disconnect(u32 clnt_hdl)
EXPORT_SYMBOL(ipa_disconnect);
/**
* ipa_clear_endpoint_delay() - Clear ep_delay.
* @clnt_hdl: [in] IPA client handle
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
* ipa_clear_endpoint_delay() - Clear ep_delay.
* @clnt_hdl: [in] IPA client handle
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_clear_endpoint_delay(u32 clnt_hdl)
{
int ret;
@ -358,13 +358,13 @@ int ipa_clear_endpoint_delay(u32 clnt_hdl)
EXPORT_SYMBOL(ipa_clear_endpoint_delay);
/**
* ipa_reset_endpoint() - reset an endpoint from BAM perspective
* @clnt_hdl: [in] IPA client handle
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
* ipa_reset_endpoint() - reset an endpoint from BAM perspective
* @clnt_hdl: [in] IPA client handle
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_reset_endpoint(u32 clnt_hdl)
{
int ret;
@ -376,13 +376,13 @@ int ipa_reset_endpoint(u32 clnt_hdl)
EXPORT_SYMBOL(ipa_reset_endpoint);
/**
* ipa_disable_endpoint() - Disable an endpoint from IPA perspective
* @clnt_hdl: [in] IPA client handle
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
* ipa_disable_endpoint() - Disable an endpoint from IPA perspective
* @clnt_hdl: [in] IPA client handle
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_disable_endpoint(u32 clnt_hdl)
{
int ret;
@ -676,8 +676,28 @@ int ipa_add_hdr(struct ipa_ioc_add_hdr *hdrs)
EXPORT_SYMBOL(ipa_add_hdr);
/**
* ipa_del_hdr() - Remove the specified headers from SW and optionally commit them
* to IPA HW
* ipa_add_hdr_usr() - add the specified headers to SW and optionally
* commit them to IPA HW
* @hdrs: [inout] set of headers to add
* @user_only: [in] indicate rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only)
{
int ret;
IPA_API_DISPATCH_RETURN(ipa_add_hdr_usr, hdrs, user_only);
return ret;
}
EXPORT_SYMBOL(ipa_add_hdr_usr);
/**
* ipa_del_hdr() - Remove the specified headers from SW and optionally
* commit them to IPA HW
* @hdls: [inout] set of headers to delete
*
* Returns: 0 on success, negative on failure
@ -715,15 +735,16 @@ EXPORT_SYMBOL(ipa_commit_hdr);
* ipa_reset_hdr() - reset the current header table in SW (does not commit to
* HW)
*
* @user_only: [in] indicate delete rules installed by userspace
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_reset_hdr(void)
int ipa_reset_hdr(bool user_only)
{
int ret;
IPA_API_DISPATCH_RETURN(ipa_reset_hdr);
IPA_API_DISPATCH_RETURN(ipa_reset_hdr, user_only);
return ret;
}
@ -793,16 +814,18 @@ EXPORT_SYMBOL(ipa_copy_hdr);
* ipa_add_hdr_proc_ctx() - add the specified headers to SW
* and optionally commit them to IPA HW
* @proc_ctxs: [inout] set of processing context headers to add
* @user_only: [in] indicate rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs)
int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only)
{
int ret;
IPA_API_DISPATCH_RETURN(ipa_add_hdr_proc_ctx, proc_ctxs);
IPA_API_DISPATCH_RETURN(ipa_add_hdr_proc_ctx, proc_ctxs, user_only);
return ret;
}
@ -847,6 +870,26 @@ int ipa_add_rt_rule(struct ipa_ioc_add_rt_rule *rules)
}
EXPORT_SYMBOL(ipa_add_rt_rule);
/**
* ipa_add_rt_rule_usr() - Add the specified routing rules to SW and optionally
* commit to IPA HW
* @rules: [inout] set of routing rules to add
* @user_only: [in] indicate rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only)
{
int ret;
IPA_API_DISPATCH_RETURN(ipa_add_rt_rule_usr, rules, user_only);
return ret;
}
EXPORT_SYMBOL(ipa_add_rt_rule_usr);
/**
* ipa_del_rt_rule() - Remove the specified routing rules to SW and optionally
* commit to IPA HW
@ -889,16 +932,17 @@ EXPORT_SYMBOL(ipa_commit_rt);
* ipa_reset_rt() - reset the current SW routing table of specified type
* (does not commit to HW)
* @ip: The family of routing tables
* @user_only: [in] indicate delete rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_reset_rt(enum ipa_ip_type ip)
int ipa_reset_rt(enum ipa_ip_type ip, bool user_only)
{
int ret;
IPA_API_DISPATCH_RETURN(ipa_reset_rt, ip);
IPA_API_DISPATCH_RETURN(ipa_reset_rt, ip, user_only);
return ret;
}
@ -981,6 +1025,7 @@ EXPORT_SYMBOL(ipa_mdfy_rt_rule);
/**
* ipa_add_flt_rule() - Add the specified filtering rules to SW and optionally
* commit to IPA HW
* @rules: [inout] set of filtering rules to add
*
* Returns: 0 on success, negative on failure
*
@ -996,6 +1041,26 @@ int ipa_add_flt_rule(struct ipa_ioc_add_flt_rule *rules)
}
EXPORT_SYMBOL(ipa_add_flt_rule);
/**
* ipa_add_flt_rule_usr() - Add the specified filtering rules to
* SW and optionally commit to IPA HW
* @rules: [inout] set of filtering rules to add
* @user_only: [in] indicate rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only)
{
int ret;
IPA_API_DISPATCH_RETURN(ipa_add_flt_rule_usr, rules, user_only);
return ret;
}
EXPORT_SYMBOL(ipa_add_flt_rule_usr);
/**
* ipa_del_flt_rule() - Remove the specified filtering rules from SW and
* optionally commit to IPA HW
@ -1054,17 +1119,18 @@ EXPORT_SYMBOL(ipa_commit_flt);
/**
* ipa_reset_flt() - Reset the current SW filtering table of specified type
* (does not commit to HW)
* @ip: [in] the family of routing tables
* @ip: [in] the family of routing tables
* @user_only: [in] indicate delete rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa_reset_flt(enum ipa_ip_type ip)
int ipa_reset_flt(enum ipa_ip_type ip, bool user_only)
{
int ret;
IPA_API_DISPATCH_RETURN(ipa_reset_flt, ip);
IPA_API_DISPATCH_RETURN(ipa_reset_flt, ip, user_only);
return ret;
}
@ -1710,20 +1776,20 @@ int ipa_uc_dereg_rdyCB(void)
EXPORT_SYMBOL(ipa_uc_dereg_rdyCB);
/**
* teth_bridge_init() - Initialize the Tethering bridge driver
* @params - in/out params for USB initialization API (please look at struct
* definition for more info)
*
* USB driver gets a pointer to a callback function (usb_notify_cb) and an
* associated data. USB driver installs this callback function in the call to
* ipa_connect().
*
* Builds IPA resource manager dependency graph.
*
* Return codes: 0: success,
* -EINVAL - Bad parameter
* Other negative value - Failure
*/
* teth_bridge_init() - Initialize the Tethering bridge driver
* @params - in/out params for USB initialization API (please look at struct
* definition for more info)
*
* USB driver gets a pointer to a callback function (usb_notify_cb) and an
* associated data. USB driver installs this callback function in the call to
* ipa_connect().
*
* Builds IPA resource manager dependency graph.
*
* Return codes: 0: success,
* -EINVAL - Bad parameter
* Other negative value - Failure
*/
int teth_bridge_init(struct teth_bridge_init_params *params)
{
int ret;
@ -1735,8 +1801,8 @@ int teth_bridge_init(struct teth_bridge_init_params *params)
EXPORT_SYMBOL(teth_bridge_init);
/**
* teth_bridge_disconnect() - Disconnect tethering bridge module
*/
* teth_bridge_disconnect() - Disconnect tethering bridge module
*/
int teth_bridge_disconnect(enum ipa_client_type client)
{
int ret;
@ -1748,14 +1814,14 @@ int teth_bridge_disconnect(enum ipa_client_type client)
EXPORT_SYMBOL(teth_bridge_disconnect);
/**
* teth_bridge_connect() - Connect bridge for a tethered Rmnet / MBIM call
* @connect_params: Connection info
*
* Return codes: 0: success
* -EINVAL: invalid parameters
* -EPERM: Operation not permitted as the bridge is already
* connected
*/
* teth_bridge_connect() - Connect bridge for a tethered Rmnet / MBIM call
* @connect_params: Connection info
*
* Return codes: 0: success
* -EINVAL: invalid parameters
* -EPERM: Operation not permitted as the bridge is already
* connected
*/
int teth_bridge_connect(struct teth_bridge_connect_params *connect_params)
{
int ret;
@ -2232,16 +2298,16 @@ int ipa_write_qmap_id(struct ipa_ioc_write_qmapid *param_in)
EXPORT_SYMBOL(ipa_write_qmap_id);
/**
* ipa_add_interrupt_handler() - Adds handler to an interrupt type
* @interrupt: Interrupt type
* @handler: The handler to be added
* @deferred_flag: whether the handler processing should be deferred in
* a workqueue
* @private_data: the client's private data
*
* Adds handler to an interrupt type and enable the specific bit
* in IRQ_EN register, associated interrupt in IRQ_STTS register will be enabled
*/
* ipa_add_interrupt_handler() - Adds handler to an interrupt type
* @interrupt: Interrupt type
* @handler: The handler to be added
* @deferred_flag: whether the handler processing should be deferred in
* a workqueue
* @private_data: the client's private data
*
* Adds handler to an interrupt type and enable the specific bit
* in IRQ_EN register, associated interrupt in IRQ_STTS register will be enabled
*/
int ipa_add_interrupt_handler(enum ipa_irq_type interrupt,
ipa_irq_handler_t handler,
bool deferred_flag,
@ -2257,11 +2323,11 @@ int ipa_add_interrupt_handler(enum ipa_irq_type interrupt,
EXPORT_SYMBOL(ipa_add_interrupt_handler);
/**
* ipa_remove_interrupt_handler() - Removes handler to an interrupt type
* @interrupt: Interrupt type
*
* Removes the handler and disable the specific bit in IRQ_EN register
*/
* ipa_remove_interrupt_handler() - Removes handler to an interrupt type
* @interrupt: Interrupt type
*
* Removes the handler and disable the specific bit in IRQ_EN register
*/
int ipa_remove_interrupt_handler(enum ipa_irq_type interrupt)
{
int ret;
@ -2273,12 +2339,12 @@ int ipa_remove_interrupt_handler(enum ipa_irq_type interrupt)
EXPORT_SYMBOL(ipa_remove_interrupt_handler);
/**
* ipa_restore_suspend_handler() - restores the original suspend IRQ handler
* as it was registered in the IPA init sequence.
* Return codes:
* 0: success
* -EPERM: failed to remove current handler or failed to add original handler
* */
* ipa_restore_suspend_handler() - restores the original suspend IRQ handler
* as it was registered in the IPA init sequence.
* Return codes:
* 0: success
* -EPERM: failed to remove current handler or failed to add original handler
*/
int ipa_restore_suspend_handler(void)
{
int ret;
@ -2621,10 +2687,10 @@ static int ipa_generic_plat_drv_probe(struct platform_device *pdev_p)
{
int result;
/*
* IPA probe function can be called for multiple times as the same probe
* function handles multiple compatibilities
*/
/**
* IPA probe function can be called for multiple times as the same probe
* function handles multiple compatibilities
*/
pr_debug("ipa: IPA driver probing started for %s\n",
pdev_p->dev.of_node->name);
@ -2747,7 +2813,7 @@ EXPORT_SYMBOL(ipa_register_ipa_ready_cb);
*
* Return codes:
* None
*/
*/
void ipa_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
{
IPA_API_DISPATCH(ipa_inc_client_enable_clks, id);
@ -2763,7 +2829,7 @@ EXPORT_SYMBOL(ipa_inc_client_enable_clks);
*
* Return codes:
* None
*/
*/
void ipa_dec_client_disable_clks(struct ipa_active_client_logging_info *id)
{
IPA_API_DISPATCH(ipa_dec_client_disable_clks, id);
@ -2793,14 +2859,14 @@ int ipa_inc_client_enable_clks_no_block(
EXPORT_SYMBOL(ipa_inc_client_enable_clks_no_block);
/**
* ipa_suspend_resource_no_block() - suspend client endpoints related to the
* IPA_RM resource and decrement active clients counter. This function is
* guaranteed to avoid sleeping.
*
* @resource: [IN] IPA Resource Manager resource
*
* Return codes: 0 on success, negative on failure.
*/
* ipa_suspend_resource_no_block() - suspend client endpoints related to the
* IPA_RM resource and decrement active clients counter. This function is
* guaranteed to avoid sleeping.
*
* @resource: [IN] IPA Resource Manager resource
*
* Return codes: 0 on success, negative on failure.
*/
int ipa_suspend_resource_no_block(enum ipa_rm_resource_name resource)
{
int ret;

View file

@ -69,11 +69,13 @@ struct ipa_api_controller {
int (*ipa_add_hdr)(struct ipa_ioc_add_hdr *hdrs);
int (*ipa_add_hdr_usr)(struct ipa_ioc_add_hdr *hdrs, bool user_only);
int (*ipa_del_hdr)(struct ipa_ioc_del_hdr *hdls);
int (*ipa_commit_hdr)(void);
int (*ipa_reset_hdr)(void);
int (*ipa_reset_hdr)(bool user_only);
int (*ipa_get_hdr)(struct ipa_ioc_get_hdr *lookup);
@ -81,17 +83,21 @@ struct ipa_api_controller {
int (*ipa_copy_hdr)(struct ipa_ioc_copy_hdr *copy);
int (*ipa_add_hdr_proc_ctx)(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs);
int (*ipa_add_hdr_proc_ctx)(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only);
int (*ipa_del_hdr_proc_ctx)(struct ipa_ioc_del_hdr_proc_ctx *hdls);
int (*ipa_add_rt_rule)(struct ipa_ioc_add_rt_rule *rules);
int (*ipa_add_rt_rule_usr)(struct ipa_ioc_add_rt_rule *rules,
bool user_only);
int (*ipa_del_rt_rule)(struct ipa_ioc_del_rt_rule *hdls);
int (*ipa_commit_rt)(enum ipa_ip_type ip);
int (*ipa_reset_rt)(enum ipa_ip_type ip);
int (*ipa_reset_rt)(enum ipa_ip_type ip, bool user_only);
int (*ipa_get_rt_tbl)(struct ipa_ioc_get_rt_tbl *lookup);
@ -103,13 +109,16 @@ struct ipa_api_controller {
int (*ipa_add_flt_rule)(struct ipa_ioc_add_flt_rule *rules);
int (*ipa_add_flt_rule_usr)(struct ipa_ioc_add_flt_rule *rules,
bool user_only);
int (*ipa_del_flt_rule)(struct ipa_ioc_del_flt_rule *hdls);
int (*ipa_mdfy_flt_rule)(struct ipa_ioc_mdfy_flt_rule *rules);
int (*ipa_commit_flt)(enum ipa_ip_type ip);
int (*ipa_reset_flt)(enum ipa_ip_type ip);
int (*ipa_reset_flt)(enum ipa_ip_type ip, bool user_only);
int (*allocate_nat_device)(struct ipa_ioc_nat_alloc_mem *mem);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -296,11 +296,13 @@ struct ipa_mhi_connect_params_internal {
* @link: entry's link in global header offset entries list
* @offset: the offset
* @bin: bin
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa_hdr_offset_entry {
struct list_head link;
u32 offset;
u32 bin;
bool ipacm_installed;
};
extern const char *ipa_clients_strings[];

View file

@ -279,6 +279,28 @@ int ipa2_active_clients_log_print_table(char *buf, int size)
return cnt;
}
static int ipa2_clean_modem_rule(void)
{
struct ipa_install_fltr_rule_req_msg_v01 *req;
int val = 0;
req = kzalloc(
sizeof(struct ipa_install_fltr_rule_req_msg_v01),
GFP_KERNEL);
if (!req) {
IPAERR("mem allocated failed!\n");
return -ENOMEM;
}
req->filter_spec_list_valid = false;
req->filter_spec_list_len = 0;
req->source_pipe_index_valid = 0;
val = qmi_filter_request_send(req);
kfree(req);
return val;
}
static int ipa2_active_clients_panic_notifier(struct notifier_block *this,
unsigned long event, void *ptr)
{
@ -531,7 +553,8 @@ static void ipa_wan_msg_free_cb(void *buff, u32 len, u32 type)
kfree(buff);
}
static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache)
static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type,
bool is_cache)
{
int retval;
struct ipa_wan_msg *wan_msg;
@ -716,7 +739,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
if (ipa2_add_hdr((struct ipa_ioc_add_hdr *)param)) {
if (ipa2_add_hdr_usr((struct ipa_ioc_add_hdr *)param,
true)) {
retval = -EFAULT;
break;
}
@ -796,7 +820,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
if (ipa2_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) {
if (ipa2_add_rt_rule_usr((struct ipa_ioc_add_rt_rule *)param,
true)) {
retval = -EFAULT;
break;
}
@ -915,7 +940,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
if (ipa2_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) {
if (ipa2_add_flt_rule_usr((struct ipa_ioc_add_flt_rule *)param,
true)) {
retval = -EFAULT;
break;
}
@ -1009,19 +1035,19 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = ipa2_commit_hdr();
break;
case IPA_IOC_RESET_HDR:
retval = ipa2_reset_hdr();
retval = ipa2_reset_hdr(false);
break;
case IPA_IOC_COMMIT_RT:
retval = ipa2_commit_rt(arg);
break;
case IPA_IOC_RESET_RT:
retval = ipa2_reset_rt(arg);
retval = ipa2_reset_rt(arg, false);
break;
case IPA_IOC_COMMIT_FLT:
retval = ipa2_commit_flt(arg);
break;
case IPA_IOC_RESET_FLT:
retval = ipa2_reset_flt(arg);
retval = ipa2_reset_flt(arg, false);
break;
case IPA_IOC_GET_RT_TBL:
if (copy_from_user(header, (u8 *)arg,
@ -1401,7 +1427,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
break;
}
if (ipa2_add_hdr_proc_ctx(
(struct ipa_ioc_add_hdr_proc_ctx *)param)) {
(struct ipa_ioc_add_hdr_proc_ctx *)param, true)) {
retval = -EFAULT;
break;
}
@ -1465,7 +1491,22 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
default: /* redundant, as cmd was checked against MAXNR */
case IPA_IOC_CLEANUP:
/*Route and filter rules will also be clean*/
IPADBG("Got IPA_IOC_CLEANUP\n");
retval = ipa2_reset_hdr(true);
memset(&nat_del, 0, sizeof(nat_del));
nat_del.table_index = 0;
retval = ipa2_nat_del_cmd(&nat_del);
retval = ipa2_clean_modem_rule();
break;
case IPA_IOC_QUERY_WLAN_CLIENT:
IPADBG("Got IPA_IOC_QUERY_WLAN_CLIENT\n");
retval = ipa2_resend_wlan_msg();
break;
default:
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return -ENOTTY;
}
@ -1478,7 +1519,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/**
* ipa_setup_dflt_rt_tables() - Setup default routing tables
*
* Return codes:
* 0: success
* -ENOMEM: failed to allocate memory
@ -4301,6 +4342,10 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
init_waitqueue_head(&ipa_ctx->msg_waitq);
mutex_init(&ipa_ctx->msg_lock);
/* store wlan client-connect-msg-list */
INIT_LIST_HEAD(&ipa_ctx->msg_wlan_client_list);
mutex_init(&ipa_ctx->msg_wlan_client_lock);
mutex_init(&ipa_ctx->lock);
mutex_init(&ipa_ctx->nat_mem.lock);
mutex_init(&ipa_ctx->ipa_cne_evt_lock);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -1008,7 +1008,7 @@ fail_desc:
static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip,
const struct ipa_flt_rule *rule, u8 add_rear,
u32 *rule_hdl)
u32 *rule_hdl, bool user)
{
struct ipa_flt_entry *entry;
struct ipa_rt_tbl *rt_tbl = NULL;
@ -1076,6 +1076,7 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip,
}
*rule_hdl = id;
entry->id = id;
entry->ipacm_installed = user;
IPADBG_LOW("add flt rule rule_cnt=%d\n", tbl->rule_cnt);
return 0;
@ -1198,12 +1199,12 @@ static int __ipa_add_global_flt_rule(enum ipa_ip_type ip,
tbl = &ipa_ctx->glob_flt_tbl[ip];
IPADBG_LOW("add global flt rule ip=%d\n", ip);
return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl);
return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl, false);
}
static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,
const struct ipa_flt_rule *rule, u8 add_rear,
u32 *rule_hdl)
u32 *rule_hdl, bool user)
{
struct ipa_flt_tbl *tbl;
int ipa_ep_idx;
@ -1225,18 +1226,34 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,
tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][ip];
IPADBG_LOW("add ep flt rule ip=%d ep=%d\n", ip, ep);
return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl);
return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl, user);
}
/**
* ipa2_add_flt_rule() - Add the specified filtering rules to SW and optionally
* commit to IPA HW
* @rules: [inout] set of filtering rules to add
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules)
{
return ipa2_add_flt_rule_usr(rules, false);
}
/**
* ipa2_add_flt_rule_usr() - Add the specified filtering rules
* to SW and optionally commit to IPA HW
* @rules: [inout] set of filtering rules to add
* @user_only: [in] indicate rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only)
{
int i;
int result;
@ -1259,7 +1276,8 @@ int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules)
result = __ipa_add_ep_flt_rule(rules->ip, rules->ep,
&rules->rules[i].rule,
rules->rules[i].at_rear,
&rules->rules[i].flt_rule_hdl);
&rules->rules[i].flt_rule_hdl,
user_only);
if (result) {
IPAERR_RL("failed to add flt rule %d\n", i);
rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED;
@ -1396,13 +1414,14 @@ bail:
/**
* ipa2_reset_flt() - Reset the current SW filtering table of specified type
* (does not commit to HW)
* @ip: [in] the family of routing tables
* @ip: [in] the family of routing tables
* @user_only: [in] indicate rules deleted by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_reset_flt(enum ipa_ip_type ip)
int ipa2_reset_flt(enum ipa_ip_type ip, bool user_only)
{
struct ipa_flt_tbl *tbl;
struct ipa_flt_entry *entry;
@ -1435,16 +1454,19 @@ int ipa2_reset_flt(enum ipa_ip_type ip)
IPA_INVALID_L4_PROTOCOL))
continue;
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt--;
entry->cookie = 0;
id = entry->id;
kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
if (!user_only ||
entry->ipacm_installed) {
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt--;
entry->cookie = 0;
id = entry->id;
kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
/* remove the handle from the database */
ipa_id_remove(id);
/* remove the handle from the database */
ipa_id_remove(id);
}
}
for (i = 0; i < ipa_ctx->ipa_num_pipes; i++) {
@ -1456,16 +1478,21 @@ int ipa2_reset_flt(enum ipa_ip_type ip)
mutex_unlock(&ipa_ctx->lock);
return -EFAULT;
}
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt--;
entry->cookie = 0;
id = entry->id;
kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
/* remove the handle from the database */
ipa_id_remove(id);
if (!user_only ||
entry->ipacm_installed) {
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt--;
entry->cookie = 0;
id = entry->id;
kmem_cache_free(ipa_ctx->flt_rule_cache,
entry);
/* remove the handle from the database */
ipa_id_remove(id);
}
}
}
mutex_unlock(&ipa_ctx->lock);
@ -1485,14 +1512,14 @@ void ipa_install_dflt_flt_rules(u32 ipa_ep_idx)
tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
rule.action = IPA_PASS_TO_EXCEPTION;
__ipa_add_flt_rule(tbl, IPA_IP_v4, &rule, true,
&ep->dflt_flt4_rule_hdl);
&ep->dflt_flt4_rule_hdl, false);
ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v4);
tbl->sticky_rear = true;
tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
rule.action = IPA_PASS_TO_EXCEPTION;
__ipa_add_flt_rule(tbl, IPA_IP_v6, &rule, true,
&ep->dflt_flt6_rule_hdl);
&ep->dflt_flt6_rule_hdl, false);
ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v6);
tbl->sticky_rear = true;
mutex_unlock(&ipa_ctx->lock);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -543,7 +543,7 @@ int __ipa_commit_hdr_v2_6L(void)
}
static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
bool add_ref_hdr)
bool add_ref_hdr, bool user_only)
{
struct ipa_hdr_entry *hdr_entry;
struct ipa_hdr_proc_ctx_entry *entry;
@ -581,6 +581,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
if (add_ref_hdr)
hdr_entry->ref_cnt++;
entry->cookie = IPA_PROC_HDR_COOKIE;
entry->ipacm_installed = user_only;
needed_len = (proc_ctx->type == IPA_HDR_PROC_NONE) ?
sizeof(struct ipa_hdr_proc_ctx_add_hdr_seq) :
@ -619,6 +620,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
*/
offset->offset = htbl->end;
offset->bin = bin;
offset->ipacm_installed = user_only;
htbl->end += ipa_hdr_proc_ctx_bin_sz[bin];
list_add(&offset->link,
&htbl->head_offset_list[bin]);
@ -627,6 +629,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
offset =
list_first_entry(&htbl->head_free_offset_list[bin],
struct ipa_hdr_proc_ctx_offset_entry, link);
offset->ipacm_installed = user_only;
list_move(&offset->link, &htbl->head_offset_list[bin]);
}
@ -664,7 +667,7 @@ bad_len:
}
static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
static int __ipa_add_hdr(struct ipa_hdr_add *hdr, bool user)
{
struct ipa_hdr_entry *entry;
struct ipa_hdr_offset_entry *offset = NULL;
@ -700,6 +703,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid;
entry->eth2_ofst = hdr->eth2_ofst;
entry->cookie = IPA_HDR_COOKIE;
entry->ipacm_installed = user;
if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0])
bin = IPA_HDR_BIN0;
@ -760,6 +764,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
list_add(&offset->link,
&htbl->head_offset_list[bin]);
entry->offset_entry = offset;
offset->ipacm_installed = user;
}
} else {
entry->is_hdr_proc_ctx = false;
@ -769,6 +774,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
struct ipa_hdr_offset_entry, link);
list_move(&offset->link, &htbl->head_offset_list[bin]);
entry->offset_entry = offset;
offset->ipacm_installed = user;
}
list_add(&entry->link, &htbl->head_hdr_entry_list);
@ -800,7 +806,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
IPADBG("adding processing context for header %s\n", hdr->name);
proc_ctx.type = IPA_HDR_PROC_NONE;
proc_ctx.hdr_hdl = id;
if (__ipa_add_hdr_proc_ctx(&proc_ctx, false)) {
if (__ipa_add_hdr_proc_ctx(&proc_ctx, false, user)) {
IPAERR("failed to add hdr proc ctx\n");
goto fail_add_proc_ctx;
}
@ -959,6 +965,21 @@ int __ipa_del_hdr(u32 hdr_hdl, bool by_user)
* Note: Should not be called from atomic context
*/
int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs)
{
return ipa2_add_hdr_usr(hdrs, false);
}
/**
* ipa2_add_hdr_usr() - add the specified headers to SW
* and optionally commit them to IPA HW
* @hdrs: [inout] set of headers to add
* @user_only: [in] indicate installed from user
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only)
{
int i;
int result = -EFAULT;
@ -977,7 +998,7 @@ int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs)
IPADBG("adding %d headers to IPA driver internal data struct\n",
hdrs->num_hdrs);
for (i = 0; i < hdrs->num_hdrs; i++) {
if (__ipa_add_hdr(&hdrs->hdr[i])) {
if (__ipa_add_hdr(&hdrs->hdr[i], user_only)) {
IPAERR_RL("failed to add hdr %d\n", i);
hdrs->hdr[i].status = -1;
} else {
@ -997,7 +1018,6 @@ bail:
mutex_unlock(&ipa_ctx->lock);
return result;
}
/**
* ipa2_del_hdr_by_user() - Remove the specified headers
* from SW and optionally commit them to IPA HW
@ -1063,12 +1083,14 @@ int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls)
* ipa2_add_hdr_proc_ctx() - add the specified headers to SW
* and optionally commit them to IPA HW
* @proc_ctxs: [inout] set of processing context headers to add
* @user_only: [in] indicate installed by user-space module
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs)
int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only)
{
int i;
int result = -EFAULT;
@ -1089,7 +1111,8 @@ int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs)
IPADBG("adding %d header processing contextes to IPA driver\n",
proc_ctxs->num_proc_ctxs);
for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) {
if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) {
if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i],
true, user_only)) {
IPAERR_RL("failed to add hdr pric ctx %d\n", i);
proc_ctxs->proc_ctx[i].status = -1;
} else {
@ -1211,11 +1234,12 @@ bail:
* ipa2_reset_hdr() - reset the current header table in SW (does not commit to
* HW)
*
* @user_only: [in] indicate delete rules installed by userspace
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_reset_hdr(void)
int ipa2_reset_hdr(bool user_only)
{
struct ipa_hdr_entry *entry;
struct ipa_hdr_entry *next;
@ -1231,9 +1255,9 @@ int ipa2_reset_hdr(void)
* issue a reset on the routing module since routing rules point to
* header table entries
*/
if (ipa2_reset_rt(IPA_IP_v4))
if (ipa2_reset_rt(IPA_IP_v4, user_only))
IPAERR("fail to reset v4 rt\n");
if (ipa2_reset_rt(IPA_IP_v6))
if (ipa2_reset_rt(IPA_IP_v6, user_only))
IPAERR("fail to reset v4 rt\n");
mutex_lock(&ipa_ctx->lock);
@ -1262,21 +1286,23 @@ int ipa2_reset_hdr(void)
WARN_ON(1);
return -EFAULT;
}
if (entry->is_hdr_proc_ctx) {
dma_unmap_single(ipa_ctx->pdev,
entry->phys_base,
entry->hdr_len,
DMA_TO_DEVICE);
entry->proc_ctx = NULL;
if (!user_only || entry->ipacm_installed) {
if (entry->is_hdr_proc_ctx) {
dma_unmap_single(ipa_ctx->pdev,
entry->phys_base,
entry->hdr_len,
DMA_TO_DEVICE);
entry->proc_ctx = NULL;
}
list_del(&entry->link);
entry->ref_cnt = 0;
entry->cookie = 0;
/* remove the handle from the database */
ipa_id_remove(entry->id);
kmem_cache_free(ipa_ctx->hdr_cache, entry);
}
list_del(&entry->link);
entry->ref_cnt = 0;
entry->cookie = 0;
/* remove the handle from the database */
ipa_id_remove(entry->id);
kmem_cache_free(ipa_ctx->hdr_cache, entry);
}
for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
list_for_each_entry_safe(off_entry, off_next,
@ -1290,14 +1316,23 @@ int ipa2_reset_hdr(void)
if (off_entry->offset == 0)
continue;
list_del(&off_entry->link);
kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry);
if (!user_only ||
off_entry->ipacm_installed) {
list_del(&off_entry->link);
kmem_cache_free(ipa_ctx->hdr_offset_cache,
off_entry);
}
}
list_for_each_entry_safe(off_entry, off_next,
&ipa_ctx->hdr_tbl.head_free_offset_list[i],
link) {
list_del(&off_entry->link);
kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry);
if (!user_only ||
off_entry->ipacm_installed) {
list_del(&off_entry->link);
kmem_cache_free(ipa_ctx->hdr_offset_cache,
off_entry);
}
}
}
/* there is one header of size 8 */
@ -1316,30 +1351,43 @@ int ipa2_reset_hdr(void)
WARN_ON(1);
return -EFAULT;
}
list_del(&ctx_entry->link);
ctx_entry->ref_cnt = 0;
ctx_entry->cookie = 0;
/* remove the handle from the database */
ipa_id_remove(ctx_entry->id);
kmem_cache_free(ipa_ctx->hdr_proc_ctx_cache, ctx_entry);
if (!user_only ||
ctx_entry->ipacm_installed) {
list_del(&ctx_entry->link);
ctx_entry->ref_cnt = 0;
ctx_entry->cookie = 0;
/* remove the handle from the database */
ipa_id_remove(ctx_entry->id);
kmem_cache_free(ipa_ctx->hdr_proc_ctx_cache,
ctx_entry);
}
}
for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) {
list_for_each_entry_safe(ctx_off_entry, ctx_off_next,
&ipa_ctx->hdr_proc_ctx_tbl.head_offset_list[i],
link) {
list_del(&ctx_off_entry->link);
kmem_cache_free(ipa_ctx->hdr_proc_ctx_offset_cache,
if (!user_only ||
ctx_off_entry->ipacm_installed) {
list_del(&ctx_off_entry->link);
kmem_cache_free(
ipa_ctx->hdr_proc_ctx_offset_cache,
ctx_off_entry);
}
}
list_for_each_entry_safe(ctx_off_entry, ctx_off_next,
&ipa_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i],
link) {
list_del(&ctx_off_entry->link);
kmem_cache_free(ipa_ctx->hdr_proc_ctx_offset_cache,
ctx_off_entry);
if (!user_only ||
ctx_off_entry->ipacm_installed) {
list_del(&ctx_off_entry->link);
kmem_cache_free(
ipa_ctx->hdr_proc_ctx_offset_cache,
ctx_off_entry);
}
}
}
ipa_ctx->hdr_proc_ctx_tbl.end = 0;

View file

@ -242,6 +242,8 @@ struct ipa_smmu_cb_ctx {
* @tbl: filter table
* @rt_tbl: routing table
* @hw_len: entry's size
* @id: rule handle - globally unique
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa_flt_entry {
struct list_head link;
@ -251,6 +253,7 @@ struct ipa_flt_entry {
struct ipa_rt_tbl *rt_tbl;
u32 hw_len;
int id;
bool ipacm_installed;
};
/**
@ -305,6 +308,7 @@ struct ipa_rt_tbl {
* @is_eth2_ofst_valid: is eth2_ofst field valid?
* @eth2_ofst: offset to start of Ethernet-II/802.3 header
* @user_deleted: is the header deleted by the user?
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa_hdr_entry {
struct list_head link;
@ -323,6 +327,7 @@ struct ipa_hdr_entry {
u8 is_eth2_ofst_valid;
u16 eth2_ofst;
bool user_deleted;
bool ipacm_installed;
};
/**
@ -346,11 +351,13 @@ struct ipa_hdr_tbl {
* @link: entry's link in global processing context header offset entries list
* @offset: the offset
* @bin: bin
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa_hdr_proc_ctx_offset_entry {
struct list_head link;
u32 offset;
u32 bin;
bool ipacm_installed;
};
/**
@ -387,6 +394,7 @@ struct ipa_hdr_proc_ctx_add_hdr_cmd_seq {
* @ref_cnt: reference counter of routing table
* @id: processing context header entry id
* @user_deleted: is the hdr processing context deleted by the user?
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa_hdr_proc_ctx_entry {
struct list_head link;
@ -397,6 +405,7 @@ struct ipa_hdr_proc_ctx_entry {
u32 ref_cnt;
int id;
bool user_deleted;
bool ipacm_installed;
};
/**
@ -446,6 +455,8 @@ struct ipa_flt_tbl {
* @hdr: header table
* @proc_ctx: processing context table
* @hw_len: the length of the table
* @id: rule handle - globaly unique
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa_rt_entry {
struct list_head link;
@ -456,6 +467,7 @@ struct ipa_rt_entry {
struct ipa_hdr_proc_ctx_entry *proc_ctx;
u32 hw_len;
int id;
bool ipacm_installed;
};
/**
@ -1151,6 +1163,8 @@ struct ipa_context {
struct list_head msg_list;
struct list_head pull_msg_list;
struct mutex msg_lock;
struct list_head msg_wlan_client_list;
struct mutex msg_wlan_client_lock;
wait_queue_head_t msg_waitq;
enum ipa_hw_type ipa_hw_type;
enum ipa_hw_mode ipa_hw_mode;
@ -1441,13 +1455,15 @@ int ipa2_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl);
*/
int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs);
int ipa2_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool by_user);
int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls);
int ipa2_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user);
int ipa2_commit_hdr(void);
int ipa2_reset_hdr(void);
int ipa2_reset_hdr(bool user_only);
int ipa2_get_hdr(struct ipa_ioc_get_hdr *lookup);
@ -1458,7 +1474,8 @@ int ipa2_copy_hdr(struct ipa_ioc_copy_hdr *copy);
/*
* Header Processing Context
*/
int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs);
int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only);
int ipa2_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls);
@ -1470,11 +1487,14 @@ int ipa2_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
*/
int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules);
int ipa2_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules,
bool user_only);
int ipa2_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls);
int ipa2_commit_rt(enum ipa_ip_type ip);
int ipa2_reset_rt(enum ipa_ip_type ip);
int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only);
int ipa2_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup);
@ -1489,13 +1509,16 @@ int ipa2_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules);
*/
int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules);
int ipa2_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules,
bool user_only);
int ipa2_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls);
int ipa2_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules);
int ipa2_commit_flt(enum ipa_ip_type ip);
int ipa2_reset_flt(enum ipa_ip_type ip);
int ipa2_reset_flt(enum ipa_ip_type ip, bool user_only);
/*
* NAT
@ -1513,6 +1536,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del);
*/
int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff,
ipa_msg_free_fn callback);
int ipa2_resend_wlan_msg(void);
int ipa2_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback);
int ipa2_deregister_pull_msg(struct ipa_msg_meta *meta);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include "ipa_i.h"
#include <linux/msm_ipa.h>
struct ipa_intf {
char name[IPA_RESOURCE_NAME_MAX];
@ -377,6 +378,108 @@ static void ipa2_send_msg_free(void *buff, u32 len, u32 type)
kfree(buff);
}
static int wlan_msg_process(struct ipa_msg_meta *meta, void *buff)
{
struct ipa_push_msg *msg_dup;
struct ipa_wlan_msg_ex *event_ex_cur_con = NULL;
struct ipa_wlan_msg_ex *event_ex_list = NULL;
struct ipa_wlan_msg *event_ex_cur_discon = NULL;
void *data_dup = NULL;
struct ipa_push_msg *entry;
struct ipa_push_msg *next;
int cnt = 0, total = 0, max = 0;
uint8_t mac[IPA_MAC_ADDR_SIZE];
uint8_t mac2[IPA_MAC_ADDR_SIZE];
if (meta->msg_type == WLAN_CLIENT_CONNECT_EX) {
/* debug print */
event_ex_cur_con = buff;
for (cnt = 0; cnt < event_ex_cur_con->num_of_attribs; cnt++) {
if (event_ex_cur_con->attribs[cnt].attrib_type ==
WLAN_HDR_ATTRIB_MAC_ADDR) {
IPADBG("%02x:%02x:%02x:%02x:%02x:%02x,(%d)\n",
event_ex_cur_con->attribs[cnt].u.mac_addr[0],
event_ex_cur_con->attribs[cnt].u.mac_addr[1],
event_ex_cur_con->attribs[cnt].u.mac_addr[2],
event_ex_cur_con->attribs[cnt].u.mac_addr[3],
event_ex_cur_con->attribs[cnt].u.mac_addr[4],
event_ex_cur_con->attribs[cnt].u.mac_addr[5],
meta->msg_type);
}
}
mutex_lock(&ipa_ctx->msg_wlan_client_lock);
msg_dup = kzalloc(sizeof(struct ipa_push_msg), GFP_KERNEL);
if (msg_dup == NULL) {
IPAERR("fail to alloc ipa_msg container\n");
return -ENOMEM;
}
msg_dup->meta = *meta;
if (meta->msg_len > 0 && buff) {
data_dup = kmalloc(meta->msg_len, GFP_KERNEL);
if (data_dup == NULL) {
IPAERR("fail to alloc data_dup container\n");
kfree(msg_dup);
return -ENOMEM;
}
memcpy(data_dup, buff, meta->msg_len);
msg_dup->buff = data_dup;
msg_dup->callback = ipa2_send_msg_free;
}
list_add_tail(&msg_dup->link, &ipa_ctx->msg_wlan_client_list);
mutex_unlock(&ipa_ctx->msg_wlan_client_lock);
}
/* remove the cache */
if (meta->msg_type == WLAN_CLIENT_DISCONNECT) {
/* debug print */
event_ex_cur_discon = buff;
IPADBG("Mac %02x:%02x:%02x:%02x:%02x:%02x,msg %d\n",
event_ex_cur_discon->mac_addr[0],
event_ex_cur_discon->mac_addr[1],
event_ex_cur_discon->mac_addr[2],
event_ex_cur_discon->mac_addr[3],
event_ex_cur_discon->mac_addr[4],
event_ex_cur_discon->mac_addr[5],
meta->msg_type);
memcpy(mac2,
event_ex_cur_discon->mac_addr,
sizeof(mac2));
mutex_lock(&ipa_ctx->msg_wlan_client_lock);
list_for_each_entry_safe(entry, next,
&ipa_ctx->msg_wlan_client_list,
link) {
event_ex_list = entry->buff;
max = event_ex_list->num_of_attribs;
for (cnt = 0; cnt < max; cnt++) {
memcpy(mac,
event_ex_list->attribs[cnt].u.mac_addr,
sizeof(mac));
if (event_ex_list->attribs[cnt].attrib_type ==
WLAN_HDR_ATTRIB_MAC_ADDR) {
pr_debug("%02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
/* compare to delete one*/
if (memcmp(mac2,
mac,
sizeof(mac)) == 0) {
IPADBG("clean %d\n", total);
list_del(&entry->link);
kfree(entry);
break;
}
}
}
total++;
}
mutex_unlock(&ipa_ctx->msg_wlan_client_lock);
}
return 0;
}
/**
* ipa2_send_msg() - Send "message" from kernel client to IPA driver
* @meta: [in] message meta-data
@ -404,7 +507,7 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff,
}
if (meta == NULL || (buff == NULL && callback != NULL) ||
(buff != NULL && callback == NULL)) {
(buff != NULL && callback == NULL) || buff == NULL) {
IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n",
meta, buff, callback);
return -EINVAL;
@ -436,6 +539,11 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff,
mutex_lock(&ipa_ctx->msg_lock);
list_add_tail(&msg->link, &ipa_ctx->msg_list);
/* support for softap client event cache */
if (wlan_msg_process(meta, buff))
IPAERR("wlan_msg_process failed\n");
/* unlock only after process */
mutex_unlock(&ipa_ctx->msg_lock);
IPA_STATS_INC_CNT(ipa_ctx->stats.msg_w[meta->msg_type]);
@ -446,6 +554,73 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff,
return 0;
}
/**
* ipa2_resend_wlan_msg() - Resend cached "message" to IPACM
*
* resend wlan client connect events to user-space
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_resend_wlan_msg(void)
{
struct ipa_wlan_msg_ex *event_ex_list = NULL;
struct ipa_push_msg *entry;
struct ipa_push_msg *next;
int cnt = 0, total = 0;
struct ipa_push_msg *msg;
void *data = NULL;
IPADBG("\n");
mutex_lock(&ipa_ctx->msg_wlan_client_lock);
list_for_each_entry_safe(entry, next, &ipa_ctx->msg_wlan_client_list,
link) {
event_ex_list = entry->buff;
for (cnt = 0; cnt < event_ex_list->num_of_attribs; cnt++) {
if (event_ex_list->attribs[cnt].attrib_type ==
WLAN_HDR_ATTRIB_MAC_ADDR) {
IPADBG("%d-Mac %02x:%02x:%02x:%02x:%02x:%02x\n",
total,
event_ex_list->attribs[cnt].u.mac_addr[0],
event_ex_list->attribs[cnt].u.mac_addr[1],
event_ex_list->attribs[cnt].u.mac_addr[2],
event_ex_list->attribs[cnt].u.mac_addr[3],
event_ex_list->attribs[cnt].u.mac_addr[4],
event_ex_list->attribs[cnt].u.mac_addr[5]);
}
}
msg = kzalloc(sizeof(struct ipa_push_msg), GFP_KERNEL);
if (msg == NULL) {
IPAERR("fail to alloc ipa_msg container\n");
mutex_unlock(&ipa_ctx->msg_wlan_client_lock);
return -ENOMEM;
}
msg->meta = entry->meta;
data = kmalloc(entry->meta.msg_len, GFP_KERNEL);
if (data == NULL) {
IPAERR("fail to alloc data container\n");
kfree(msg);
mutex_unlock(&ipa_ctx->msg_wlan_client_lock);
return -ENOMEM;
}
memcpy(data, entry->buff, entry->meta.msg_len);
msg->buff = data;
msg->callback = ipa2_send_msg_free;
mutex_lock(&ipa_ctx->msg_lock);
list_add_tail(&msg->link, &ipa_ctx->msg_list);
mutex_unlock(&ipa_ctx->msg_lock);
wake_up(&ipa_ctx->msg_waitq);
total++;
}
mutex_unlock(&ipa_ctx->msg_wlan_client_lock);
return 0;
}
/**
* ipa2_register_pull_msg() - register pull message type
* @meta: [in] message meta-data

View file

@ -785,12 +785,6 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del)
base_addr = ipa_ctx->nat_mem.tmp_dma_handle;
}
if (del->public_ip_addr == 0) {
IPADBG("Bad Parameter\n");
result = -EPERM;
goto bail;
}
memset(&desc, 0, sizeof(desc));
/* NO-OP IC for ensuring that IPA pipeline is empty */
reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -514,6 +514,14 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req)
int rc;
int i;
/* check if modem up */
if (!qmi_indication_fin ||
!qmi_modem_init_fin ||
!ipa_q6_clnt) {
IPAWANDBG("modem QMI haven't up yet\n");
return -EINVAL;
}
/* check if the filter rules from IPACM is valid */
if (req->filter_spec_list_len == 0) {
IPAWANDBG("IPACM pass zero rules to Q6\n");

View file

@ -1026,7 +1026,8 @@ static int __ipa_del_rt_tbl(struct ipa_rt_tbl *entry)
}
static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl)
const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl,
bool user)
{
struct ipa_rt_tbl *tbl;
struct ipa_rt_entry *entry;
@ -1101,6 +1102,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
IPADBG_LOW("rule_cnt=%d\n", tbl->rule_cnt);
*rule_hdl = id;
entry->id = id;
entry->ipacm_installed = user;
return 0;
@ -1125,6 +1127,21 @@ error:
* Note: Should not be called from atomic context
*/
int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules)
{
return ipa2_add_rt_rule_usr(rules, false);
}
/**
* ipa2_add_rt_rule_usr() - Add the specified routing rules to SW and optionally
* commit to IPA HW
* @rules: [inout] set of routing rules to add
* @user_only: [in] indicate installed by userspace module
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only)
{
int i;
int ret;
@ -1139,7 +1156,8 @@ int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules)
if (__ipa_add_rt_rule(rules->ip, rules->rt_tbl_name,
&rules->rules[i].rule,
rules->rules[i].at_rear,
&rules->rules[i].rt_rule_hdl)) {
&rules->rules[i].rt_rule_hdl,
user_only)) {
IPAERR_RL("failed to add rt rule %d\n", i);
rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
} else {
@ -1308,13 +1326,14 @@ bail:
/**
* ipa2_reset_rt() - reset the current SW routing table of specified type
* (does not commit to HW)
* @ip: The family of routing tables
* @ip: [in] The family of routing tables
* @user_only: [in] indicate delete rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa2_reset_rt(enum ipa_ip_type ip)
int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only)
{
struct ipa_rt_tbl *tbl;
struct ipa_rt_tbl *tbl_next;
@ -1324,6 +1343,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip)
struct ipa_rt_tbl_set *rset;
u32 apps_start_idx;
int id;
bool tbl_user = false;
if (ip >= IPA_IP_MAX) {
IPAERR_RL("bad parm\n");
@ -1343,7 +1363,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip)
* issue a reset on the filtering module of same IP type since
* filtering rules point to routing tables
*/
if (ipa2_reset_flt(ip))
if (ipa2_reset_flt(ip, user_only))
IPAERR_RL("fail to reset flt ip=%d\n", ip);
set = &ipa_ctx->rt_tbl_set[ip];
@ -1351,6 +1371,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip)
mutex_lock(&ipa_ctx->lock);
IPADBG("reset rt ip=%d\n", ip);
list_for_each_entry_safe(tbl, tbl_next, &set->head_rt_tbl_list, link) {
tbl_user = false;
list_for_each_entry_safe(rule, rule_next,
&tbl->head_rt_rule_list, link) {
if (ipa_id_find(rule->id) == NULL) {
@ -1359,25 +1380,34 @@ int ipa2_reset_rt(enum ipa_ip_type ip)
return -EFAULT;
}
/* indicate if tbl used for user-specified rules*/
if (rule->ipacm_installed) {
IPADBG("tbl_user %d, tbl-index %d\n",
tbl_user, tbl->id);
tbl_user = true;
}
/*
* for the "default" routing tbl, remove all but the
* last rule
*/
if (tbl->idx == apps_start_idx && tbl->rule_cnt == 1)
continue;
if (!user_only ||
rule->ipacm_installed) {
list_del(&rule->link);
tbl->rule_cnt--;
if (rule->hdr)
__ipa_release_hdr(rule->hdr->id);
else if (rule->proc_ctx)
__ipa_release_hdr_proc_ctx(
rule->proc_ctx->id);
rule->cookie = 0;
id = rule->id;
kmem_cache_free(ipa_ctx->rt_rule_cache, rule);
list_del(&rule->link);
tbl->rule_cnt--;
if (rule->hdr)
__ipa_release_hdr(rule->hdr->id);
else if (rule->proc_ctx)
__ipa_release_hdr_proc_ctx(rule->proc_ctx->id);
rule->cookie = 0;
id = rule->id;
kmem_cache_free(ipa_ctx->rt_rule_cache, rule);
/* remove the handle from the database */
ipa_id_remove(id);
/* remove the handle from the database */
ipa_id_remove(id);
}
}
if (ipa_id_find(tbl->id) == NULL) {
@ -1389,24 +1419,28 @@ int ipa2_reset_rt(enum ipa_ip_type ip)
/* do not remove the "default" routing tbl which has index 0 */
if (tbl->idx != apps_start_idx) {
if (!tbl->in_sys) {
list_del(&tbl->link);
set->tbl_cnt--;
clear_bit(tbl->idx,
&ipa_ctx->rt_idx_bitmap[ip]);
IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n",
tbl->idx, set->tbl_cnt);
kmem_cache_free(ipa_ctx->rt_tbl_cache, tbl);
} else {
list_move(&tbl->link, &rset->head_rt_tbl_list);
clear_bit(tbl->idx,
&ipa_ctx->rt_idx_bitmap[ip]);
set->tbl_cnt--;
IPADBG("rst sys rt tbl_idx=%d tbl_cnt=%d\n",
tbl->idx, set->tbl_cnt);
if (!user_only || tbl_user) {
if (!tbl->in_sys) {
list_del(&tbl->link);
set->tbl_cnt--;
clear_bit(tbl->idx,
&ipa_ctx->rt_idx_bitmap[ip]);
IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n",
tbl->idx, set->tbl_cnt);
kmem_cache_free(ipa_ctx->rt_tbl_cache,
tbl);
} else {
list_move(&tbl->link,
&rset->head_rt_tbl_list);
clear_bit(tbl->idx,
&ipa_ctx->rt_idx_bitmap[ip]);
set->tbl_cnt--;
IPADBG("rst tbl_idx=%d cnt=%d\n",
tbl->idx, set->tbl_cnt);
}
/* remove the handle from the database */
ipa_id_remove(id);
}
/* remove the handle from the database */
ipa_id_remove(id);
}
}
mutex_unlock(&ipa_ctx->lock);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -5078,6 +5078,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_cfg_ep_holb_by_client = ipa2_cfg_ep_holb_by_client;
api_ctrl->ipa_cfg_ep_ctrl = ipa2_cfg_ep_ctrl;
api_ctrl->ipa_add_hdr = ipa2_add_hdr;
api_ctrl->ipa_add_hdr_usr = ipa2_add_hdr_usr;
api_ctrl->ipa_del_hdr = ipa2_del_hdr;
api_ctrl->ipa_commit_hdr = ipa2_commit_hdr;
api_ctrl->ipa_reset_hdr = ipa2_reset_hdr;
@ -5087,6 +5088,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_add_hdr_proc_ctx = ipa2_add_hdr_proc_ctx;
api_ctrl->ipa_del_hdr_proc_ctx = ipa2_del_hdr_proc_ctx;
api_ctrl->ipa_add_rt_rule = ipa2_add_rt_rule;
api_ctrl->ipa_add_rt_rule_usr = ipa2_add_rt_rule_usr;
api_ctrl->ipa_del_rt_rule = ipa2_del_rt_rule;
api_ctrl->ipa_commit_rt = ipa2_commit_rt;
api_ctrl->ipa_reset_rt = ipa2_reset_rt;
@ -5095,6 +5097,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_query_rt_index = ipa2_query_rt_index;
api_ctrl->ipa_mdfy_rt_rule = ipa2_mdfy_rt_rule;
api_ctrl->ipa_add_flt_rule = ipa2_add_flt_rule;
api_ctrl->ipa_add_flt_rule_usr = ipa2_add_flt_rule_usr;
api_ctrl->ipa_del_flt_rule = ipa2_del_flt_rule;
api_ctrl->ipa_mdfy_flt_rule = ipa2_mdfy_flt_rule;
api_ctrl->ipa_commit_flt = ipa2_commit_flt;

View file

@ -345,6 +345,43 @@ int ipa3_active_clients_log_print_table(char *buf, int size)
return cnt;
}
static int ipa3_clean_modem_rule(void)
{
struct ipa_install_fltr_rule_req_msg_v01 *req;
struct ipa_install_fltr_rule_req_ex_msg_v01 *req_ex;
int val = 0;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v3_0) {
req = kzalloc(
sizeof(struct ipa_install_fltr_rule_req_msg_v01),
GFP_KERNEL);
if (!req) {
IPAERR("mem allocated failed!\n");
return -ENOMEM;
}
req->filter_spec_list_valid = false;
req->filter_spec_list_len = 0;
req->source_pipe_index_valid = 0;
val = ipa3_qmi_filter_request_send(req);
kfree(req);
} else {
req_ex = kzalloc(
sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01),
GFP_KERNEL);
if (!req_ex) {
IPAERR("mem allocated failed!\n");
return -ENOMEM;
}
req_ex->filter_spec_ex_list_valid = false;
req_ex->filter_spec_ex_list_len = 0;
req_ex->source_pipe_index_valid = 0;
val = ipa3_qmi_filter_request_ex_send(req_ex);
kfree(req_ex);
}
return val;
}
static int ipa3_active_clients_panic_notifier(struct notifier_block *this,
unsigned long event, void *ptr)
{
@ -598,7 +635,8 @@ static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type)
kfree(buff);
}
static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache)
static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type,
bool is_cache)
{
int retval;
struct ipa_wan_msg *wan_msg;
@ -906,7 +944,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
if (ipa3_add_hdr((struct ipa_ioc_add_hdr *)param)) {
if (ipa3_add_hdr_usr((struct ipa_ioc_add_hdr *)param,
true)) {
retval = -EFAULT;
break;
}
@ -986,7 +1025,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
if (ipa3_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) {
if (ipa3_add_rt_rule_usr((struct ipa_ioc_add_rt_rule *)param,
true)) {
retval = -EFAULT;
break;
}
@ -1191,7 +1231,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
if (ipa3_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) {
if (ipa3_add_flt_rule_usr((struct ipa_ioc_add_flt_rule *)param,
true)) {
retval = -EFAULT;
break;
}
@ -1328,19 +1369,19 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = ipa3_commit_hdr();
break;
case IPA_IOC_RESET_HDR:
retval = ipa3_reset_hdr();
retval = ipa3_reset_hdr(false);
break;
case IPA_IOC_COMMIT_RT:
retval = ipa3_commit_rt(arg);
break;
case IPA_IOC_RESET_RT:
retval = ipa3_reset_rt(arg);
retval = ipa3_reset_rt(arg, false);
break;
case IPA_IOC_COMMIT_FLT:
retval = ipa3_commit_flt(arg);
break;
case IPA_IOC_RESET_FLT:
retval = ipa3_reset_flt(arg);
retval = ipa3_reset_flt(arg, false);
break;
case IPA_IOC_GET_RT_TBL:
if (copy_from_user(header, (u8 *)arg,
@ -1720,7 +1761,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
break;
}
if (ipa3_add_hdr_proc_ctx(
(struct ipa_ioc_add_hdr_proc_ctx *)param)) {
(struct ipa_ioc_add_hdr_proc_ctx *)param, true)) {
retval = -EFAULT;
break;
}
@ -1812,7 +1853,22 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
default: /* redundant, as cmd was checked against MAXNR */
case IPA_IOC_CLEANUP:
/*Route and filter rules will also be clean*/
IPADBG("Got IPA_IOC_CLEANUP\n");
retval = ipa3_reset_hdr(true);
memset(&nat_del, 0, sizeof(nat_del));
nat_del.table_index = 0;
retval = ipa3_nat_del_cmd(&nat_del);
retval = ipa3_clean_modem_rule();
break;
case IPA_IOC_QUERY_WLAN_CLIENT:
IPADBG("Got IPA_IOC_QUERY_WLAN_CLIENT\n");
retval = ipa3_resend_wlan_msg();
break;
default:
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return -ENOTTY;
}
@ -1823,13 +1879,13 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
/**
* ipa3_setup_dflt_rt_tables() - Setup default routing tables
*
* Return codes:
* 0: success
* -ENOMEM: failed to allocate memory
* -EPERM: failed to add the tables
*/
* ipa3_setup_dflt_rt_tables() - Setup default routing tables
*
* Return codes:
* 0: success
* -ENOMEM: failed to allocate memory
* -EPERM: failed to add the tables
*/
int ipa3_setup_dflt_rt_tables(void)
{
struct ipa_ioc_add_rt_rule *rt_rule;
@ -2010,14 +2066,14 @@ static int ipa3_init_smem_region(int memory_region_size,
}
/**
* ipa3_init_q6_smem() - Initialize Q6 general memory and
* header memory regions in IPA.
*
* Return codes:
* 0: success
* -ENOMEM: failed to allocate dma memory
* -EFAULT: failed to send IPA command to initialize the memory
*/
* ipa3_init_q6_smem() - Initialize Q6 general memory and
* header memory regions in IPA.
*
* Return codes:
* 0: success
* -ENOMEM: failed to allocate dma memory
* -EFAULT: failed to send IPA command to initialize the memory
*/
int ipa3_init_q6_smem(void)
{
int rc;
@ -2546,12 +2602,12 @@ static int ipa3_q6_set_ex_path_to_apps(void)
}
/**
* ipa3_q6_pre_shutdown_cleanup() - A cleanup for all Q6 related configuration
* in IPA HW. This is performed in case of SSR.
*
* This is a mandatory procedure, in case one of the steps fails, the
* AP needs to restart.
*/
* ipa3_q6_pre_shutdown_cleanup() - A cleanup for all Q6 related configuration
* in IPA HW. This is performed in case of SSR.
*
* This is a mandatory procedure, in case one of the steps fails, the
* AP needs to restart.
*/
void ipa3_q6_pre_shutdown_cleanup(void)
{
IPADBG_LOW("ENTER\n");
@ -2569,8 +2625,8 @@ void ipa3_q6_pre_shutdown_cleanup(void)
BUG();
}
/* Remove delay from Q6 PRODs to avoid pending descriptors
* on pipe reset procedure
*/
* on pipe reset procedure
*/
ipa3_q6_pipe_delay(false);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
@ -3465,11 +3521,11 @@ static unsigned int ipa3_get_bus_vote(void)
}
/**
* ipa3_enable_clks() - Turn on IPA clocks
*
* Return codes:
* None
*/
* ipa3_enable_clks() - Turn on IPA clocks
*
* Return codes:
* None
*/
void ipa3_enable_clks(void)
{
IPADBG("enabling IPA clocks and bus voting\n");
@ -3498,11 +3554,11 @@ void _ipa_disable_clks_v3_0(void)
}
/**
* ipa3_disable_clks() - Turn off IPA clocks
*
* Return codes:
* None
*/
* ipa3_disable_clks() - Turn off IPA clocks
*
* Return codes:
* None
*/
void ipa3_disable_clks(void)
{
IPADBG("disabling IPA clocks and bus voting\n");
@ -3541,28 +3597,28 @@ static void ipa3_start_tag_process(struct work_struct *work)
}
/**
* ipa3_active_clients_log_mod() - Log a modification in the active clients
* reference count
*
* This method logs any modification in the active clients reference count:
* It logs the modification in the circular history buffer
* It logs the modification in the hash table - looking for an entry,
* creating one if needed and deleting one if needed.
*
* @id: ipa3_active client logging info struct to hold the log information
* @inc: a boolean variable to indicate whether the modification is an increase
* or decrease
* @int_ctx: a boolean variable to indicate whether this call is being made from
* an interrupt context and therefore should allocate GFP_ATOMIC memory
*
* Method process:
* - Hash the unique identifier string
* - Find the hash in the table
* 1)If found, increase or decrease the reference count
* 2)If not found, allocate a new hash table entry struct and initialize it
* - Remove and deallocate unneeded data structure
* - Log the call in the circular history buffer (unless it is a simple call)
*/
* ipa3_active_clients_log_mod() - Log a modification in the active clients
* reference count
*
* This method logs any modification in the active clients reference count:
* It logs the modification in the circular history buffer
* It logs the modification in the hash table - looking for an entry,
* creating one if needed and deleting one if needed.
*
* @id: ipa3_active client logging info struct to hold the log information
* @inc: a boolean variable to indicate whether the modification is an increase
* or decrease
* @int_ctx: a boolean variable to indicate whether this call is being made from
* an interrupt context and therefore should allocate GFP_ATOMIC memory
*
* Method process:
* - Hash the unique identifier string
* - Find the hash in the table
* 1)If found, increase or decrease the reference count
* 2)If not found, allocate a new hash table entry struct and initialize it
* - Remove and deallocate unneeded data structure
* - Log the call in the circular history buffer (unless it is a simple call)
*/
void ipa3_active_clients_log_mod(struct ipa_active_client_logging_info *id,
bool inc, bool int_ctx)
{
@ -3632,12 +3688,12 @@ void ipa3_active_clients_log_inc(struct ipa_active_client_logging_info *id,
}
/**
* ipa3_inc_client_enable_clks() - Increase active clients counter, and
* enable ipa clocks if necessary
*
* Return codes:
* None
*/
* ipa3_inc_client_enable_clks() - Increase active clients counter, and
* enable ipa clocks if necessary
*
* Return codes:
* None
*/
void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
{
ipa3_active_clients_lock();
@ -3650,13 +3706,13 @@ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
}
/**
* ipa3_inc_client_enable_clks_no_block() - Only increment the number of active
* clients if no asynchronous actions should be done. Asynchronous actions are
* locking a mutex and waking up IPA HW.
*
* Return codes: 0 for success
* -EPERM if an asynchronous action should have been done
*/
* ipa3_inc_client_enable_clks_no_block() - Only increment the number of active
* clients if no asynchronous actions should be done. Asynchronous actions are
* locking a mutex and waking up IPA HW.
*
* Return codes: 0 for success
* -EPERM if an asynchronous action should have been done
*/
int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info
*id)
{
@ -3718,12 +3774,12 @@ void ipa3_dec_client_disable_clks(struct ipa_active_client_logging_info *id)
}
/**
* ipa3_inc_acquire_wakelock() - Increase active clients counter, and
* acquire wakelock if necessary
*
* Return codes:
* None
*/
* ipa3_inc_acquire_wakelock() - Increase active clients counter, and
* acquire wakelock if necessary
*
* Return codes:
* None
*/
void ipa3_inc_acquire_wakelock(void)
{
unsigned long flags;
@ -3835,12 +3891,12 @@ static void ipa3_sps_process_irq_schedule_rel(void)
}
/**
* ipa3_suspend_handler() - Handles the suspend interrupt:
* wakes up the suspended peripheral by requesting its consumer
* @interrupt: Interrupt type
* @private_data: The client's private data
* @interrupt_data: Interrupt specific information data
*/
* ipa3_suspend_handler() - Handles the suspend interrupt:
* wakes up the suspended peripheral by requesting its consumer
* @interrupt: Interrupt type
* @private_data: The client's private data
* @interrupt_data: Interrupt specific information data
*/
void ipa3_suspend_handler(enum ipa_irq_type interrupt,
void *private_data,
void *interrupt_data)
@ -3903,12 +3959,12 @@ void ipa3_suspend_handler(enum ipa_irq_type interrupt,
}
/**
* ipa3_restore_suspend_handler() - restores the original suspend IRQ handler
* as it was registered in the IPA init sequence.
* Return codes:
* 0: success
* -EPERM: failed to remove current handler or failed to add original handler
* */
* ipa3_restore_suspend_handler() - restores the original suspend IRQ handler
* as it was registered in the IPA init sequence.
* Return codes:
* 0: success
* -EPERM: failed to remove current handler or failed to add original handler
*/
int ipa3_restore_suspend_handler(void)
{
int result = 0;
@ -4497,39 +4553,37 @@ static int ipa3_tz_unlock_reg(struct ipa3_context *ipa3_ctx)
}
/**
* ipa3_pre_init() - Initialize the IPA Driver.
* This part contains all initialization which doesn't require IPA HW, such
* as structure allocations and initializations, register writes, etc.
*
* @resource_p: contain platform specific values from DST file
* @pdev: The platform device structure representing the IPA driver
*
* Function initialization process:
* - Allocate memory for the driver context data struct
* - Initializing the ipa3_ctx with:
* 1)parsed values from the dts file
* 2)parameters passed to the module initialization
* 3)read HW values(such as core memory size)
* - Map IPA core registers to CPU memory
* - Restart IPA core(HW reset)
* - Set configuration for IPA BAM via BAM_CNFG_BITS
* - Initialize the look-aside caches(kmem_cache/slab) for filter,
* routing and IPA-tree
* - Create memory pool with 4 objects for DMA operations(each object
* is 512Bytes long), this object will be use for tx(A5->IPA)
* - Initialize lists head(routing,filter,hdr,system pipes)
* - Initialize mutexes (for ipa_ctx and NAT memory mutexes)
* - Initialize spinlocks (for list related to A5<->IPA pipes)
* - Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq"
* - Initialize Red-Black-Tree(s) for handles of header,routing rule,
* routing table ,filtering rule
* - Initialize the filter block by committing IPV4 and IPV6 default rules
* - Create empty routing table in system memory(no committing)
* - Initialize pipes memory pool with ipa3_pipe_mem_init for supported platforms
* - Create a char-device for IPA
* - Initialize IPA RM (resource manager)
* - Configure GSI registers (in GSI case)
*/
* ipa3_pre_init() - Initialize the IPA Driver.
* This part contains all initialization which doesn't require IPA HW, such
* as structure allocations and initializations, register writes, etc.
*
* @resource_p: contain platform specific values from DST file
* @pdev: The platform device structure representing the IPA driver
*
* Function initialization process:
* Allocate memory for the driver context data struct
* Initializing the ipa3_ctx with :
* 1)parsed values from the dts file
* 2)parameters passed to the module initialization
* 3)read HW values(such as core memory size)
* Map IPA core registers to CPU memory
* Restart IPA core(HW reset)
* Initialize the look-aside caches(kmem_cache/slab) for filter,
* routing and IPA-tree
* Create memory pool with 4 objects for DMA operations(each object
* is 512Bytes long), this object will be use for tx(A5->IPA)
* Initialize lists head(routing, hdr, system pipes)
* Initialize mutexes (for ipa_ctx and NAT memory mutexes)
* Initialize spinlocks (for list related to A5<->IPA pipes)
* Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq"
* Initialize Red-Black-Tree(s) for handles of header,routing rule,
* routing table ,filtering rule
* Initialize the filter block by committing IPV4 and IPV6 default rules
* Create empty routing table in system memory(no committing)
* Create a char-device for IPA
* Initialize IPA RM (resource manager)
* Configure GSI registers (in GSI case)
*/
static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
struct device *ipa_dev)
{
@ -4887,6 +4941,10 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
init_waitqueue_head(&ipa3_ctx->msg_waitq);
mutex_init(&ipa3_ctx->msg_lock);
/* store wlan client-connect-msg-list */
INIT_LIST_HEAD(&ipa3_ctx->msg_wlan_client_list);
mutex_init(&ipa3_ctx->msg_wlan_client_lock);
mutex_init(&ipa3_ctx->lock);
mutex_init(&ipa3_ctx->nat_mem.lock);
mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
@ -5873,7 +5931,7 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
*
* Returns -EAGAIN to runtime_pm framework in case IPA is in use by AP.
* This will postpone the suspend operation until IPA is no longer used by AP.
*/
*/
int ipa3_ap_suspend(struct device *dev)
{
int i;
@ -5899,14 +5957,14 @@ int ipa3_ap_suspend(struct device *dev)
}
/**
* ipa3_ap_resume() - resume callback for runtime_pm
* @dev: pointer to device
*
* This callback will be invoked by the runtime_pm framework when an AP resume
* operation is invoked.
*
* Always returns 0 since resume should always succeed.
*/
* ipa3_ap_resume() - resume callback for runtime_pm
* @dev: pointer to device
*
* This callback will be invoked by the runtime_pm framework when an AP resume
* operation is invoked.
*
* Always returns 0 since resume should always succeed.
*/
int ipa3_ap_resume(struct device *dev)
{
return 0;

View file

@ -784,7 +784,7 @@ error:
static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry,
const struct ipa_flt_rule *rule, struct ipa3_rt_tbl *rt_tbl,
struct ipa3_flt_tbl *tbl)
struct ipa3_flt_tbl *tbl, bool user)
{
int id;
@ -809,6 +809,7 @@ static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry,
}
}
(*entry)->rule_id = id;
(*entry)->ipacm_installed = user;
return 0;
@ -846,7 +847,7 @@ ipa_insert_failed:
static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
const struct ipa_flt_rule *rule, u8 add_rear,
u32 *rule_hdl)
u32 *rule_hdl, bool user)
{
struct ipa3_flt_entry *entry;
struct ipa3_rt_tbl *rt_tbl = NULL;
@ -854,7 +855,7 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
if (__ipa_validate_flt_rule(rule, &rt_tbl, ip))
goto error;
if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl))
if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl, user))
goto error;
if (add_rear) {
@ -904,7 +905,7 @@ static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl,
if (__ipa_validate_flt_rule(rule, &rt_tbl, ip))
goto error;
if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl))
if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl, true))
goto error;
list_add(&entry->link, &((*add_after_entry)->link));
@ -1054,7 +1055,7 @@ static int __ipa_add_flt_get_ep_idx(enum ipa_client_type ep, int *ipa_ep_idx)
static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,
const struct ipa_flt_rule *rule, u8 add_rear,
u32 *rule_hdl)
u32 *rule_hdl, bool user)
{
struct ipa3_flt_tbl *tbl;
int ipa_ep_idx;
@ -1072,18 +1073,33 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,
tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][ip];
IPADBG_LOW("add ep flt rule ip=%d ep=%d\n", ip, ep);
return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl);
return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl, user);
}
/**
* ipa3_add_flt_rule() - Add the specified filtering rules to SW and optionally
* commit to IPA HW
* @rules: [inout] set of filtering rules to add
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules)
{
return ipa3_add_flt_rule_usr(rules, false);
}
/**
* ipa3_add_flt_rule_usr() - Add the specified filtering rules to
* SW and optionally commit to IPA HW
* @rules: [inout] set of filtering rules to add
* @user_only: [in] indicate rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only)
{
int i;
int result;
@ -1100,7 +1116,8 @@ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules)
result = __ipa_add_ep_flt_rule(rules->ip, rules->ep,
&rules->rules[i].rule,
rules->rules[i].at_rear,
&rules->rules[i].flt_rule_hdl);
&rules->rules[i].flt_rule_hdl,
user_only);
else
result = -1;
@ -1347,18 +1364,20 @@ bail:
* ipa3_reset_flt() - Reset the current SW filtering table of specified type
* (does not commit to HW)
* @ip: [in] the family of routing tables
* @user_only: [in] indicate rules deleted by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_reset_flt(enum ipa_ip_type ip)
int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only)
{
struct ipa3_flt_tbl *tbl;
struct ipa3_flt_entry *entry;
struct ipa3_flt_entry *next;
int i;
int id;
int rule_id;
if (ip >= IPA_IP_MAX) {
IPAERR_RL("bad parm\n");
@ -1378,21 +1397,27 @@ int ipa3_reset_flt(enum ipa_ip_type ip)
mutex_unlock(&ipa3_ctx->lock);
return -EFAULT;
}
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt--;
/* if rule id was allocated from idr, remove it */
if ((entry->rule_id < ipahal_get_rule_id_hi_bit()) &&
(entry->rule_id >= ipahal_get_low_rule_id()))
idr_remove(&entry->tbl->rule_ids,
entry->rule_id);
entry->cookie = 0;
id = entry->id;
kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
/* remove the handle from the database */
ipa3_id_remove(id);
if (!user_only ||
entry->ipacm_installed) {
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt--;
/* if rule id was allocated from idr, remove */
rule_id = entry->rule_id;
id = entry->id;
if ((rule_id < ipahal_get_rule_id_hi_bit()) &&
(rule_id >= ipahal_get_low_rule_id()))
idr_remove(&entry->tbl->rule_ids,
rule_id);
entry->cookie = 0;
kmem_cache_free(ipa3_ctx->flt_rule_cache,
entry);
/* remove the handle from the database */
ipa3_id_remove(id);
}
}
}
mutex_unlock(&ipa3_ctx->lock);
@ -1418,14 +1443,14 @@ void ipa3_install_dflt_flt_rules(u32 ipa_ep_idx)
tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
rule.action = IPA_PASS_TO_EXCEPTION;
__ipa_add_flt_rule(tbl, IPA_IP_v4, &rule, true,
&ep->dflt_flt4_rule_hdl);
&ep->dflt_flt4_rule_hdl, false);
ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v4);
tbl->sticky_rear = true;
tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
rule.action = IPA_PASS_TO_EXCEPTION;
__ipa_add_flt_rule(tbl, IPA_IP_v6, &rule, true,
&ep->dflt_flt6_rule_hdl);
&ep->dflt_flt6_rule_hdl, false);
ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v6);
tbl->sticky_rear = true;
mutex_unlock(&ipa3_ctx->lock);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -315,7 +315,7 @@ end:
}
static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
bool add_ref_hdr)
bool add_ref_hdr, bool user_only)
{
struct ipa3_hdr_entry *hdr_entry;
struct ipa3_hdr_proc_ctx_entry *entry;
@ -360,6 +360,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
if (add_ref_hdr)
hdr_entry->ref_cnt++;
entry->cookie = IPA_PROC_HDR_COOKIE;
entry->ipacm_installed = user_only;
needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type);
@ -396,6 +397,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
*/
offset->offset = htbl->end;
offset->bin = bin;
offset->ipacm_installed = user_only;
htbl->end += ipa_hdr_proc_ctx_bin_sz[bin];
list_add(&offset->link,
&htbl->head_offset_list[bin]);
@ -404,6 +406,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
offset =
list_first_entry(&htbl->head_free_offset_list[bin],
struct ipa3_hdr_proc_ctx_offset_entry, link);
offset->ipacm_installed = user_only;
list_move(&offset->link, &htbl->head_offset_list[bin]);
}
@ -441,7 +444,7 @@ bad_len:
}
static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
static int __ipa_add_hdr(struct ipa_hdr_add *hdr, bool user)
{
struct ipa3_hdr_entry *entry;
struct ipa_hdr_offset_entry *offset = NULL;
@ -476,6 +479,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid;
entry->eth2_ofst = hdr->eth2_ofst;
entry->cookie = IPA_HDR_COOKIE;
entry->ipacm_installed = user;
if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0])
bin = IPA_HDR_BIN0;
@ -527,6 +531,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
list_add(&offset->link,
&htbl->head_offset_list[bin]);
entry->offset_entry = offset;
offset->ipacm_installed = user;
}
} else {
entry->is_hdr_proc_ctx = false;
@ -535,6 +540,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
struct ipa_hdr_offset_entry, link);
list_move(&offset->link, &htbl->head_offset_list[bin]);
entry->offset_entry = offset;
offset->ipacm_installed = user;
}
list_add(&entry->link, &htbl->head_hdr_entry_list);
@ -566,7 +572,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
IPADBG("adding processing context for header %s\n", hdr->name);
proc_ctx.type = IPA_HDR_PROC_NONE;
proc_ctx.hdr_hdl = id;
if (__ipa_add_hdr_proc_ctx(&proc_ctx, false)) {
if (__ipa_add_hdr_proc_ctx(&proc_ctx, false, user)) {
IPAERR("failed to add hdr proc ctx\n");
goto fail_add_proc_ctx;
}
@ -727,6 +733,21 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user)
* Note: Should not be called from atomic context
*/
int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs)
{
return ipa3_add_hdr_usr(hdrs, false);
}
/**
* ipa3_add_hdr_usr() - add the specified headers to SW
* and optionally commit them to IPA HW
* @hdrs: [inout] set of headers to add
* @user_only: [in] indicate installed from user
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only)
{
int i;
int result = -EFAULT;
@ -740,7 +761,7 @@ int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs)
IPADBG("adding %d headers to IPA driver internal data struct\n",
hdrs->num_hdrs);
for (i = 0; i < hdrs->num_hdrs; i++) {
if (__ipa_add_hdr(&hdrs->hdr[i])) {
if (__ipa_add_hdr(&hdrs->hdr[i], user_only)) {
IPAERR_RL("failed to add hdr %d\n", i);
hdrs->hdr[i].status = -1;
} else {
@ -821,12 +842,14 @@ int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls)
* ipa3_add_hdr_proc_ctx() - add the specified headers to SW
* and optionally commit them to IPA HW
* @proc_ctxs: [inout] set of processing context headers to add
* @user_only: [in] indicate installed by user-space module
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs)
int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only)
{
int i;
int result = -EFAULT;
@ -840,7 +863,8 @@ int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs)
IPADBG("adding %d header processing contextes to IPA driver\n",
proc_ctxs->num_proc_ctxs);
for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) {
if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) {
if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i],
true, user_only)) {
IPAERR_RL("failed to add hdr pric ctx %d\n", i);
proc_ctxs->proc_ctx[i].status = -1;
} else {
@ -955,11 +979,12 @@ bail:
* ipa3_reset_hdr() - reset the current header table in SW (does not commit to
* HW)
*
* @user_only: [in] indicate delete rules installed by userspace
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_reset_hdr(void)
int ipa3_reset_hdr(bool user_only)
{
struct ipa3_hdr_entry *entry;
struct ipa3_hdr_entry *next;
@ -975,9 +1000,9 @@ int ipa3_reset_hdr(void)
* issue a reset on the routing module since routing rules point to
* header table entries
*/
if (ipa3_reset_rt(IPA_IP_v4))
if (ipa3_reset_rt(IPA_IP_v4, user_only))
IPAERR("fail to reset v4 rt\n");
if (ipa3_reset_rt(IPA_IP_v6))
if (ipa3_reset_rt(IPA_IP_v6, user_only))
IPAERR("fail to reset v4 rt\n");
mutex_lock(&ipa3_ctx->lock);
@ -1006,21 +1031,23 @@ int ipa3_reset_hdr(void)
WARN_ON(1);
return -EFAULT;
}
if (entry->is_hdr_proc_ctx) {
dma_unmap_single(ipa3_ctx->pdev,
entry->phys_base,
entry->hdr_len,
DMA_TO_DEVICE);
entry->proc_ctx = NULL;
if (!user_only || entry->ipacm_installed) {
if (entry->is_hdr_proc_ctx) {
dma_unmap_single(ipa3_ctx->pdev,
entry->phys_base,
entry->hdr_len,
DMA_TO_DEVICE);
entry->proc_ctx = NULL;
}
list_del(&entry->link);
entry->ref_cnt = 0;
entry->cookie = 0;
/* remove the handle from the database */
ipa3_id_remove(entry->id);
kmem_cache_free(ipa3_ctx->hdr_cache, entry);
}
list_del(&entry->link);
entry->ref_cnt = 0;
entry->cookie = 0;
/* remove the handle from the database */
ipa3_id_remove(entry->id);
kmem_cache_free(ipa3_ctx->hdr_cache, entry);
}
for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
list_for_each_entry_safe(off_entry, off_next,
@ -1034,14 +1061,23 @@ int ipa3_reset_hdr(void)
if (off_entry->offset == 0)
continue;
list_del(&off_entry->link);
kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry);
if (!user_only ||
off_entry->ipacm_installed) {
list_del(&off_entry->link);
kmem_cache_free(ipa3_ctx->hdr_offset_cache,
off_entry);
}
}
list_for_each_entry_safe(off_entry, off_next,
&ipa3_ctx->hdr_tbl.head_free_offset_list[i],
link) {
list_del(&off_entry->link);
kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry);
if (!user_only ||
off_entry->ipacm_installed) {
list_del(&off_entry->link);
kmem_cache_free(ipa3_ctx->hdr_offset_cache,
off_entry);
}
}
}
/* there is one header of size 8 */
@ -1060,30 +1096,43 @@ int ipa3_reset_hdr(void)
WARN_ON(1);
return -EFAULT;
}
list_del(&ctx_entry->link);
ctx_entry->ref_cnt = 0;
ctx_entry->cookie = 0;
/* remove the handle from the database */
ipa3_id_remove(ctx_entry->id);
kmem_cache_free(ipa3_ctx->hdr_proc_ctx_cache, ctx_entry);
if (!user_only ||
ctx_entry->ipacm_installed) {
list_del(&ctx_entry->link);
ctx_entry->ref_cnt = 0;
ctx_entry->cookie = 0;
/* remove the handle from the database */
ipa3_id_remove(ctx_entry->id);
kmem_cache_free(ipa3_ctx->hdr_proc_ctx_cache,
ctx_entry);
}
}
for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) {
list_for_each_entry_safe(ctx_off_entry, ctx_off_next,
&ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i],
link) {
list_del(&ctx_off_entry->link);
kmem_cache_free(ipa3_ctx->hdr_proc_ctx_offset_cache,
if (!user_only ||
ctx_off_entry->ipacm_installed) {
list_del(&ctx_off_entry->link);
kmem_cache_free(
ipa3_ctx->hdr_proc_ctx_offset_cache,
ctx_off_entry);
}
}
list_for_each_entry_safe(ctx_off_entry, ctx_off_next,
&ipa3_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i],
link) {
list_del(&ctx_off_entry->link);
kmem_cache_free(ipa3_ctx->hdr_proc_ctx_offset_cache,
ctx_off_entry);
if (!user_only ||
ctx_off_entry->ipacm_installed) {
list_del(&ctx_off_entry->link);
kmem_cache_free(
ipa3_ctx->hdr_proc_ctx_offset_cache,
ctx_off_entry);
}
}
}
ipa3_ctx->hdr_proc_ctx_tbl.end = 0;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -233,6 +233,7 @@ struct ipa_smmu_cb_ctx {
* @prio: rule 10bit priority which defines the order of the rule
* among other rules at the same integrated table
* @rule_id: rule 10bit ID to be returned in packet status
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa3_flt_entry {
struct list_head link;
@ -244,6 +245,7 @@ struct ipa3_flt_entry {
int id;
u16 prio;
u16 rule_id;
bool ipacm_installed;
};
/**
@ -300,6 +302,7 @@ struct ipa3_rt_tbl {
* @is_eth2_ofst_valid: is eth2_ofst field valid?
* @eth2_ofst: offset to start of Ethernet-II/802.3 header
* @user_deleted: is the header deleted by the user?
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa3_hdr_entry {
struct list_head link;
@ -318,6 +321,7 @@ struct ipa3_hdr_entry {
u8 is_eth2_ofst_valid;
u16 eth2_ofst;
bool user_deleted;
bool ipacm_installed;
};
/**
@ -341,11 +345,13 @@ struct ipa3_hdr_tbl {
* @link: entry's link in global processing context header offset entries list
* @offset: the offset
* @bin: bin
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa3_hdr_proc_ctx_offset_entry {
struct list_head link;
u32 offset;
u32 bin;
bool ipacm_installed;
};
/**
@ -358,6 +364,7 @@ struct ipa3_hdr_proc_ctx_offset_entry {
* @ref_cnt: reference counter of routing table
* @id: processing context header entry id
* @user_deleted: is the hdr processing context deleted by the user?
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa3_hdr_proc_ctx_entry {
struct list_head link;
@ -368,6 +375,7 @@ struct ipa3_hdr_proc_ctx_entry {
u32 ref_cnt;
int id;
bool user_deleted;
bool ipacm_installed;
};
/**
@ -423,6 +431,8 @@ struct ipa3_flt_tbl {
* @prio: rule 10bit priority which defines the order of the rule
* among other rules at the integrated same table
* @rule_id: rule 10bit ID to be returned in packet status
* @rule_id_valid: indicate if rule_id_valid valid or not?
* @ipacm_installed: indicate if installed by ipacm
*/
struct ipa3_rt_entry {
struct list_head link;
@ -436,6 +446,7 @@ struct ipa3_rt_entry {
u16 prio;
u16 rule_id;
u16 rule_id_valid;
bool ipacm_installed;
};
/**
@ -1217,6 +1228,8 @@ struct ipa3_context {
struct list_head msg_list;
struct list_head pull_msg_list;
struct mutex msg_lock;
struct list_head msg_wlan_client_list;
struct mutex msg_wlan_client_lock;
wait_queue_head_t msg_waitq;
enum ipa_hw_type ipa_hw_type;
enum ipa3_hw_mode ipa3_hw_mode;
@ -1591,13 +1604,15 @@ int ipa3_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl);
*/
int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs);
int ipa3_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool by_user);
int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls);
int ipa3_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user);
int ipa3_commit_hdr(void);
int ipa3_reset_hdr(void);
int ipa3_reset_hdr(bool user_only);
int ipa3_get_hdr(struct ipa_ioc_get_hdr *lookup);
@ -1608,7 +1623,8 @@ int ipa3_copy_hdr(struct ipa_ioc_copy_hdr *copy);
/*
* Header Processing Context
*/
int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs);
int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only);
int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls);
@ -1620,6 +1636,9 @@ int ipa3_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
*/
int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules);
int ipa3_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules,
bool user_only);
int ipa3_add_rt_rule_ext(struct ipa_ioc_add_rt_rule_ext *rules);
int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules);
@ -1628,7 +1647,7 @@ int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls);
int ipa3_commit_rt(enum ipa_ip_type ip);
int ipa3_reset_rt(enum ipa_ip_type ip);
int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only);
int ipa3_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup);
@ -1643,6 +1662,9 @@ int ipa3_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules);
*/
int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules);
int ipa3_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules,
bool user_only);
int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules);
int ipa3_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls);
@ -1651,7 +1673,7 @@ int ipa3_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules);
int ipa3_commit_flt(enum ipa_ip_type ip);
int ipa3_reset_flt(enum ipa_ip_type ip);
int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only);
/*
* NAT
@ -1672,6 +1694,7 @@ int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del);
*/
int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff,
ipa_msg_free_fn callback);
int ipa3_resend_wlan_msg(void);
int ipa3_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback);
int ipa3_deregister_pull_msg(struct ipa_msg_meta *meta);
@ -1704,7 +1727,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
* To transfer multiple data packets
* While passing the data descriptor list, the anchor node
* should be of type struct ipa_tx_data_desc not list_head
*/
*/
int ipa3_tx_dp_mul(enum ipa_client_type dst,
struct ipa_tx_data_desc *data_desc);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include "ipa_i.h"
#include <linux/msm_ipa.h>
struct ipa3_intf {
char name[IPA_RESOURCE_NAME_MAX];
@ -387,6 +388,108 @@ static void ipa3_send_msg_free(void *buff, u32 len, u32 type)
kfree(buff);
}
static int wlan_msg_process(struct ipa_msg_meta *meta, void *buff)
{
struct ipa3_push_msg *msg_dup;
struct ipa_wlan_msg_ex *event_ex_cur_con = NULL;
struct ipa_wlan_msg_ex *event_ex_list = NULL;
struct ipa_wlan_msg *event_ex_cur_discon = NULL;
void *data_dup = NULL;
struct ipa3_push_msg *entry;
struct ipa3_push_msg *next;
int cnt = 0, total = 0, max = 0;
uint8_t mac[IPA_MAC_ADDR_SIZE];
uint8_t mac2[IPA_MAC_ADDR_SIZE];
if (meta->msg_type == WLAN_CLIENT_CONNECT_EX) {
/* debug print */
event_ex_cur_con = buff;
for (cnt = 0; cnt < event_ex_cur_con->num_of_attribs; cnt++) {
if (event_ex_cur_con->attribs[cnt].attrib_type ==
WLAN_HDR_ATTRIB_MAC_ADDR) {
IPADBG("%02x:%02x:%02x:%02x:%02x:%02x,(%d)\n",
event_ex_cur_con->attribs[cnt].u.mac_addr[0],
event_ex_cur_con->attribs[cnt].u.mac_addr[1],
event_ex_cur_con->attribs[cnt].u.mac_addr[2],
event_ex_cur_con->attribs[cnt].u.mac_addr[3],
event_ex_cur_con->attribs[cnt].u.mac_addr[4],
event_ex_cur_con->attribs[cnt].u.mac_addr[5],
meta->msg_type);
}
}
mutex_lock(&ipa3_ctx->msg_wlan_client_lock);
msg_dup = kzalloc(sizeof(struct ipa3_push_msg), GFP_KERNEL);
if (msg_dup == NULL) {
IPAERR("fail to alloc ipa_msg container\n");
return -ENOMEM;
}
msg_dup->meta = *meta;
if (meta->msg_len > 0 && buff) {
data_dup = kmalloc(meta->msg_len, GFP_KERNEL);
if (data_dup == NULL) {
IPAERR("fail to alloc data_dup container\n");
kfree(msg_dup);
return -ENOMEM;
}
memcpy(data_dup, buff, meta->msg_len);
msg_dup->buff = data_dup;
msg_dup->callback = ipa3_send_msg_free;
}
list_add_tail(&msg_dup->link, &ipa3_ctx->msg_wlan_client_list);
mutex_unlock(&ipa3_ctx->msg_wlan_client_lock);
}
/* remove the cache */
if (meta->msg_type == WLAN_CLIENT_DISCONNECT) {
/* debug print */
event_ex_cur_discon = buff;
IPADBG("Mac %02x:%02x:%02x:%02x:%02x:%02x,msg %d\n",
event_ex_cur_discon->mac_addr[0],
event_ex_cur_discon->mac_addr[1],
event_ex_cur_discon->mac_addr[2],
event_ex_cur_discon->mac_addr[3],
event_ex_cur_discon->mac_addr[4],
event_ex_cur_discon->mac_addr[5],
meta->msg_type);
memcpy(mac2,
event_ex_cur_discon->mac_addr,
sizeof(mac2));
mutex_lock(&ipa3_ctx->msg_wlan_client_lock);
list_for_each_entry_safe(entry, next,
&ipa3_ctx->msg_wlan_client_list,
link) {
event_ex_list = entry->buff;
max = event_ex_list->num_of_attribs;
for (cnt = 0; cnt < max; cnt++) {
memcpy(mac,
event_ex_list->attribs[cnt].u.mac_addr,
sizeof(mac));
if (event_ex_list->attribs[cnt].attrib_type ==
WLAN_HDR_ATTRIB_MAC_ADDR) {
pr_debug("%02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
/* compare to delete one*/
if (memcmp(mac2,
mac,
sizeof(mac)) == 0) {
IPADBG("clean %d\n", total);
list_del(&entry->link);
kfree(entry);
break;
}
}
}
total++;
}
mutex_unlock(&ipa3_ctx->msg_wlan_client_lock);
}
return 0;
}
/**
* ipa3_send_msg() - Send "message" from kernel client to IPA driver
* @meta: [in] message meta-data
@ -409,7 +512,7 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff,
void *data = NULL;
if (meta == NULL || (buff == NULL && callback != NULL) ||
(buff != NULL && callback == NULL)) {
(buff != NULL && callback == NULL) || buff == NULL) {
IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n",
meta, buff, callback);
return -EINVAL;
@ -441,6 +544,11 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff,
mutex_lock(&ipa3_ctx->msg_lock);
list_add_tail(&msg->link, &ipa3_ctx->msg_list);
/* support for softap client event cache */
if (wlan_msg_process(meta, buff))
IPAERR("wlan_msg_process failed\n");
/* unlock only after process */
mutex_unlock(&ipa3_ctx->msg_lock);
IPA_STATS_INC_CNT(ipa3_ctx->stats.msg_w[meta->msg_type]);
@ -451,6 +559,73 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff,
return 0;
}
/**
* ipa3_resend_wlan_msg() - Resend cached "message" to IPACM
*
* resend wlan client connect events to user-space
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_resend_wlan_msg(void)
{
struct ipa_wlan_msg_ex *event_ex_list = NULL;
struct ipa3_push_msg *entry;
struct ipa3_push_msg *next;
int cnt = 0, total = 0;
struct ipa3_push_msg *msg;
void *data = NULL;
IPADBG("\n");
mutex_lock(&ipa3_ctx->msg_wlan_client_lock);
list_for_each_entry_safe(entry, next, &ipa3_ctx->msg_wlan_client_list,
link) {
event_ex_list = entry->buff;
for (cnt = 0; cnt < event_ex_list->num_of_attribs; cnt++) {
if (event_ex_list->attribs[cnt].attrib_type ==
WLAN_HDR_ATTRIB_MAC_ADDR) {
IPADBG("%d-Mac %02x:%02x:%02x:%02x:%02x:%02x\n",
total,
event_ex_list->attribs[cnt].u.mac_addr[0],
event_ex_list->attribs[cnt].u.mac_addr[1],
event_ex_list->attribs[cnt].u.mac_addr[2],
event_ex_list->attribs[cnt].u.mac_addr[3],
event_ex_list->attribs[cnt].u.mac_addr[4],
event_ex_list->attribs[cnt].u.mac_addr[5]);
}
}
msg = kzalloc(sizeof(struct ipa3_push_msg), GFP_KERNEL);
if (msg == NULL) {
IPAERR("fail to alloc ipa_msg container\n");
mutex_unlock(&ipa3_ctx->msg_wlan_client_lock);
return -ENOMEM;
}
msg->meta = entry->meta;
data = kmalloc(entry->meta.msg_len, GFP_KERNEL);
if (data == NULL) {
IPAERR("fail to alloc data container\n");
kfree(msg);
mutex_unlock(&ipa3_ctx->msg_wlan_client_lock);
return -ENOMEM;
}
memcpy(data, entry->buff, entry->meta.msg_len);
msg->buff = data;
msg->callback = ipa3_send_msg_free;
mutex_lock(&ipa3_ctx->msg_lock);
list_add_tail(&msg->link, &ipa3_ctx->msg_list);
mutex_unlock(&ipa3_ctx->msg_lock);
wake_up(&ipa3_ctx->msg_waitq);
total++;
}
mutex_unlock(&ipa3_ctx->msg_wlan_client_lock);
return 0;
}
/**
* ipa3_register_pull_msg() - register pull message type
* @meta: [in] message meta-data

View file

@ -605,6 +605,14 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req)
int rc;
int i;
/* check if modem up */
if (!ipa3_qmi_indication_fin ||
!ipa3_qmi_modem_init_fin ||
!ipa_q6_clnt) {
IPAWANDBG("modem QMI haven't up yet\n");
return -EINVAL;
}
/* check if the filter rules from IPACM is valid */
if (req->filter_spec_list_len == 0)
IPAWANDBG("IPACM pass zero rules to Q6\n");
@ -688,6 +696,14 @@ int ipa3_qmi_filter_request_ex_send(
int rc;
int i;
/* check if modem up */
if (!ipa3_qmi_indication_fin ||
!ipa3_qmi_modem_init_fin ||
!ipa_q6_clnt) {
IPAWANDBG("modem QMI haven't up yet\n");
return -EINVAL;
}
/* check if the filter rules from IPACM is valid */
if (req->filter_spec_ex_list_len == 0) {
IPAWANDBG("IPACM pass zero rules to Q6\n");

View file

@ -940,7 +940,7 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry,
const struct ipa_rt_rule *rule,
struct ipa3_rt_tbl *tbl, struct ipa3_hdr_entry *hdr,
struct ipa3_hdr_proc_ctx_entry *proc_ctx,
u16 rule_id)
u16 rule_id, bool user)
{
int id;
@ -967,6 +967,7 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry,
}
}
(*(entry))->rule_id = id;
(*(entry))->ipacm_installed = user;
return 0;
@ -1012,7 +1013,7 @@ ipa_insert_failed:
static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl,
u16 rule_id)
u16 rule_id, bool user)
{
struct ipa3_rt_tbl *tbl;
struct ipa3_rt_entry *entry;
@ -1041,7 +1042,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
}
if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx,
rule_id))
rule_id, user))
goto error;
if (at_rear)
@ -1072,7 +1073,7 @@ static int __ipa_add_rt_rule_after(struct ipa3_rt_tbl *tbl,
if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx))
goto error;
if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx, 0))
if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx, 0, true))
goto error;
list_add(&entry->link, &((*add_after_entry)->link));
@ -1101,7 +1102,23 @@ error:
*
* Note: Should not be called from atomic context
*/
int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules)
{
return ipa3_add_rt_rule_usr(rules, false);
}
/**
* ipa3_add_rt_rule_usr() - Add the specified routing rules to SW and optionally
* commit to IPA HW
* @rules: [inout] set of routing rules to add
* @user_only: [in] indicate installed by userspace module
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only)
{
int i;
int ret;
@ -1117,7 +1134,8 @@ int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules)
&rules->rules[i].rule,
rules->rules[i].at_rear,
&rules->rules[i].rt_rule_hdl,
0)) {
0,
user_only)) {
IPAERR("failed to add rt rule %d\n", i);
rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
} else {
@ -1162,7 +1180,7 @@ int ipa3_add_rt_rule_ext(struct ipa_ioc_add_rt_rule_ext *rules)
&rules->rules[i].rule,
rules->rules[i].at_rear,
&rules->rules[i].rt_rule_hdl,
rules->rules[i].rule_id)) {
rules->rules[i].rule_id, true)) {
IPAERR("failed to add rt rule %d\n", i);
rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
} else {
@ -1439,13 +1457,14 @@ bail:
/**
* ipa3_reset_rt() - reset the current SW routing table of specified type
* (does not commit to HW)
* @ip: The family of routing tables
* @ip: [in] The family of routing tables
* @user_only: [in] indicate delete rules installed by userspace
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
int ipa3_reset_rt(enum ipa_ip_type ip)
int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only)
{
struct ipa3_rt_tbl *tbl;
struct ipa3_rt_tbl *tbl_next;
@ -1455,6 +1474,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip)
struct ipa3_rt_tbl_set *rset;
u32 apps_start_idx;
int id;
bool tbl_user = false;
if (ip >= IPA_IP_MAX) {
IPAERR_RL("bad parm\n");
@ -1472,7 +1492,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip)
* issue a reset on the filtering module of same IP type since
* filtering rules point to routing tables
*/
if (ipa3_reset_flt(ip))
if (ipa3_reset_flt(ip, user_only))
IPAERR_RL("fail to reset flt ip=%d\n", ip);
set = &ipa3_ctx->rt_tbl_set[ip];
@ -1480,6 +1500,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip)
mutex_lock(&ipa3_ctx->lock);
IPADBG("reset rt ip=%d\n", ip);
list_for_each_entry_safe(tbl, tbl_next, &set->head_rt_tbl_list, link) {
tbl_user = false;
list_for_each_entry_safe(rule, rule_next,
&tbl->head_rt_rule_list, link) {
if (ipa3_id_find(rule->id) == NULL) {
@ -1488,6 +1509,12 @@ int ipa3_reset_rt(enum ipa_ip_type ip)
return -EFAULT;
}
/* indicate if tbl used for user-specified rules*/
if (rule->ipacm_installed) {
IPADBG("tbl_user %d, tbl-index %d\n",
tbl_user, tbl->id);
tbl_user = true;
}
/*
* for the "default" routing tbl, remove all but the
* last rule
@ -1495,19 +1522,23 @@ int ipa3_reset_rt(enum ipa_ip_type ip)
if (tbl->idx == apps_start_idx && tbl->rule_cnt == 1)
continue;
list_del(&rule->link);
tbl->rule_cnt--;
if (rule->hdr)
__ipa3_release_hdr(rule->hdr->id);
else if (rule->proc_ctx)
__ipa3_release_hdr_proc_ctx(rule->proc_ctx->id);
rule->cookie = 0;
idr_remove(&tbl->rule_ids, rule->rule_id);
id = rule->id;
kmem_cache_free(ipa3_ctx->rt_rule_cache, rule);
if (!user_only ||
rule->ipacm_installed) {
list_del(&rule->link);
tbl->rule_cnt--;
if (rule->hdr)
__ipa3_release_hdr(rule->hdr->id);
else if (rule->proc_ctx)
__ipa3_release_hdr_proc_ctx(
rule->proc_ctx->id);
rule->cookie = 0;
idr_remove(&tbl->rule_ids, rule->rule_id);
id = rule->id;
kmem_cache_free(ipa3_ctx->rt_rule_cache, rule);
/* remove the handle from the database */
ipa3_id_remove(id);
/* remove the handle from the database */
ipa3_id_remove(id);
}
}
if (ipa3_id_find(tbl->id) == NULL) {
@ -1519,26 +1550,30 @@ int ipa3_reset_rt(enum ipa_ip_type ip)
/* do not remove the "default" routing tbl which has index 0 */
if (tbl->idx != apps_start_idx) {
idr_destroy(&tbl->rule_ids);
if (tbl->in_sys[IPA_RULE_HASHABLE] ||
tbl->in_sys[IPA_RULE_NON_HASHABLE]) {
list_move(&tbl->link, &rset->head_rt_tbl_list);
clear_bit(tbl->idx,
if (!user_only || tbl_user) {
idr_destroy(&tbl->rule_ids);
if (tbl->in_sys[IPA_RULE_HASHABLE] ||
tbl->in_sys[IPA_RULE_NON_HASHABLE]) {
list_move(&tbl->link,
&rset->head_rt_tbl_list);
clear_bit(tbl->idx,
&ipa3_ctx->rt_idx_bitmap[ip]);
set->tbl_cnt--;
IPADBG("rst sys rt tbl_idx=%d tbl_cnt=%d\n",
set->tbl_cnt--;
IPADBG("rst tbl_idx=%d cnt=%d\n",
tbl->idx, set->tbl_cnt);
} else {
list_del(&tbl->link);
set->tbl_cnt--;
clear_bit(tbl->idx,
} else {
list_del(&tbl->link);
set->tbl_cnt--;
clear_bit(tbl->idx,
&ipa3_ctx->rt_idx_bitmap[ip]);
IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n",
IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n",
tbl->idx, set->tbl_cnt);
kmem_cache_free(ipa3_ctx->rt_tbl_cache, tbl);
kmem_cache_free(ipa3_ctx->rt_tbl_cache,
tbl);
}
/* remove the handle from the database */
ipa3_id_remove(id);
}
/* remove the handle from the database */
ipa3_id_remove(id);
}
}
mutex_unlock(&ipa3_ctx->lock);
@ -1653,6 +1688,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
struct ipa3_hdr_entry *hdr_entry;
struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
if (rtrule->rule.hdr_hdl) {
hdr = ipa3_id_find(rtrule->rule.hdr_hdl);
if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -3153,6 +3153,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_cfg_ep_holb_by_client = ipa3_cfg_ep_holb_by_client;
api_ctrl->ipa_cfg_ep_ctrl = ipa3_cfg_ep_ctrl;
api_ctrl->ipa_add_hdr = ipa3_add_hdr;
api_ctrl->ipa_add_hdr_usr = ipa3_add_hdr_usr;
api_ctrl->ipa_del_hdr = ipa3_del_hdr;
api_ctrl->ipa_commit_hdr = ipa3_commit_hdr;
api_ctrl->ipa_reset_hdr = ipa3_reset_hdr;
@ -3162,6 +3163,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_add_hdr_proc_ctx = ipa3_add_hdr_proc_ctx;
api_ctrl->ipa_del_hdr_proc_ctx = ipa3_del_hdr_proc_ctx;
api_ctrl->ipa_add_rt_rule = ipa3_add_rt_rule;
api_ctrl->ipa_add_rt_rule_usr = ipa3_add_rt_rule_usr;
api_ctrl->ipa_del_rt_rule = ipa3_del_rt_rule;
api_ctrl->ipa_commit_rt = ipa3_commit_rt;
api_ctrl->ipa_reset_rt = ipa3_reset_rt;
@ -3170,6 +3172,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_query_rt_index = ipa3_query_rt_index;
api_ctrl->ipa_mdfy_rt_rule = ipa3_mdfy_rt_rule;
api_ctrl->ipa_add_flt_rule = ipa3_add_flt_rule;
api_ctrl->ipa_add_flt_rule_usr = ipa3_add_flt_rule_usr;
api_ctrl->ipa_del_flt_rule = ipa3_del_flt_rule;
api_ctrl->ipa_mdfy_flt_rule = ipa3_mdfy_flt_rule;
api_ctrl->ipa_commit_flt = ipa3_commit_flt;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -1226,11 +1226,13 @@ int ipa_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl);
*/
int ipa_add_hdr(struct ipa_ioc_add_hdr *hdrs);
int ipa_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only);
int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls);
int ipa_commit_hdr(void);
int ipa_reset_hdr(void);
int ipa_reset_hdr(bool user_only);
int ipa_get_hdr(struct ipa_ioc_get_hdr *lookup);
@ -1241,7 +1243,8 @@ int ipa_copy_hdr(struct ipa_ioc_copy_hdr *copy);
/*
* Header Processing Context
*/
int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs);
int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only);
int ipa_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls);
@ -1250,11 +1253,13 @@ int ipa_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls);
*/
int ipa_add_rt_rule(struct ipa_ioc_add_rt_rule *rules);
int ipa_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only);
int ipa_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls);
int ipa_commit_rt(enum ipa_ip_type ip);
int ipa_reset_rt(enum ipa_ip_type ip);
int ipa_reset_rt(enum ipa_ip_type ip, bool user_only);
int ipa_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup);
@ -1269,13 +1274,15 @@ int ipa_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules);
*/
int ipa_add_flt_rule(struct ipa_ioc_add_flt_rule *rules);
int ipa_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only);
int ipa_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls);
int ipa_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules);
int ipa_commit_flt(enum ipa_ip_type ip);
int ipa_reset_flt(enum ipa_ip_type ip);
int ipa_reset_flt(enum ipa_ip_type ip, bool user_only);
/*
* NAT
@ -1648,6 +1655,12 @@ static inline int ipa_add_hdr(struct ipa_ioc_add_hdr *hdrs)
return -EPERM;
}
static inline int ipa_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs,
bool user_only)
{
return -EPERM;
}
static inline int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls)
{
return -EPERM;
@ -1658,7 +1671,7 @@ static inline int ipa_commit_hdr(void)
return -EPERM;
}
static inline int ipa_reset_hdr(void)
static inline int ipa_reset_hdr(bool user_only)
{
return -EPERM;
}
@ -1682,7 +1695,8 @@ static inline int ipa_copy_hdr(struct ipa_ioc_copy_hdr *copy)
* Header Processing Context
*/
static inline int ipa_add_hdr_proc_ctx(
struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs)
struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
bool user_only)
{
return -EPERM;
}
@ -1699,6 +1713,12 @@ static inline int ipa_add_rt_rule(struct ipa_ioc_add_rt_rule *rules)
return -EPERM;
}
static inline int ipa_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules,
bool user_only)
{
return -EPERM;
}
static inline int ipa_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls)
{
return -EPERM;
@ -1709,7 +1729,7 @@ static inline int ipa_commit_rt(enum ipa_ip_type ip)
return -EPERM;
}
static inline int ipa_reset_rt(enum ipa_ip_type ip)
static inline int ipa_reset_rt(enum ipa_ip_type ip, bool user_only)
{
return -EPERM;
}
@ -1742,6 +1762,12 @@ static inline int ipa_add_flt_rule(struct ipa_ioc_add_flt_rule *rules)
return -EPERM;
}
static inline int ipa_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules,
bool user_only)
{
return -EPERM;
}
static inline int ipa_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls)
{
return -EPERM;
@ -1757,7 +1783,7 @@ static inline int ipa_commit_flt(enum ipa_ip_type ip)
return -EPERM;
}
static inline int ipa_reset_flt(enum ipa_ip_type ip)
static inline int ipa_reset_flt(enum ipa_ip_type ip, bool user_only)
{
return -EPERM;
}

View file

@ -95,7 +95,9 @@
#define IPA_IOCTL_DEL_VLAN_IFACE 53
#define IPA_IOCTL_ADD_L2TP_VLAN_MAPPING 54
#define IPA_IOCTL_DEL_L2TP_VLAN_MAPPING 55
#define IPA_IOCTL_MAX 56
#define IPA_IOCTL_CLEANUP 56
#define IPA_IOCTL_QUERY_WLAN_CLIENT 57
#define IPA_IOCTL_MAX 58
/**
* max size of the header to be inserted
@ -1912,6 +1914,10 @@ struct ipa_tether_device_info {
#define IPA_IOC_DEL_L2TP_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_DEL_L2TP_VLAN_MAPPING, \
struct ipa_ioc_l2tp_vlan_mapping_info *)
#define IPA_IOC_CLEANUP _IO(IPA_IOC_MAGIC,\
IPA_IOCTL_CLEANUP)
#define IPA_IOC_QUERY_WLAN_CLIENT _IO(IPA_IOC_MAGIC,\
IPA_IOCTL_QUERY_WLAN_CLIENT)
/*
* unique magic number of the Tethering bridge ioctls
*/