OSDN Git Service

msm: ipa: support ipacm cleanup
authorSkylar Chang <chiaweic@codeaurora.org>
Sat, 7 Apr 2018 23:42:36 +0000 (16:42 -0700)
committerGerrit - the friendly Code Review server <code-review@localhost>
Thu, 2 Aug 2018 07:37:49 +0000 (00:37 -0700)
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>
22 files changed:
drivers/platform/msm/ipa/ipa_api.c
drivers/platform/msm/ipa/ipa_api.h
drivers/platform/msm/ipa/ipa_common_i.h
drivers/platform/msm/ipa/ipa_v2/ipa.c
drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
drivers/platform/msm/ipa/ipa_v2/ipa_i.h
drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c
drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
drivers/platform/msm/ipa/ipa_v3/ipa.c
drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
drivers/platform/msm/ipa/ipa_v3/ipa_i.h
drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
include/linux/ipa.h
include/uapi/linux/msm_ipa.h

index 719a1ec..66dd016 100644 (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;
 }
@@ -848,6 +871,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
  * @hdls:      [inout] set of routing rules to delete
@@ -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
  *
@@ -997,6 +1042,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;
index 33e0f46..72db83c 100644 (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);
 
index 911db0b..00c3515 100644 (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[];
index bf46ea8..d9f8912 100644 (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);
index 834f028..6392c37 100644 (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,12 +1226,13 @@ 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
  *
@@ -1238,6 +1240,21 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,
  */
 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);
index fbbb3f2..15c8f92 100644 (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;
                }
@@ -960,6 +966,21 @@ int __ipa_del_hdr(u32 hdr_hdl, bool by_user)
  */
 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;
-               }
-               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);
+               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);
+               }
        }
        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;
index 1986dc2..1d34564 100644 (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);
 
index 9c4fc0c..da56a2e 100644 (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]);
 
@@ -447,6 +555,73 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff,
 }
 
 /**
+ * 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
  * @callback: [in] pull callback
index 1be68b3..cc3d267 100644 (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);
index e33d0d8..7855572 100644 (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");
index 7cc3c38..e4a3a72 100644 (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;
 
@@ -1126,6 +1128,21 @@ error:
  */
 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;
-
-                       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);
+                       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);
+
+                               /* 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);
index 76f74c0..f8d6e68 100644 (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;
index 681b2d9..dfff3b4 100644 (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;
index 128b859..03c846e 100644 (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,12 +1073,13 @@ 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
  *
@@ -1085,6 +1087,20 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,
  */
 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);
index b5b8643..f71eb95 100644 (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;
                }
@@ -728,6 +734,21 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user)
  */
 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;
-               }
-               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);
+               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);
+               }
        }
        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;
index 7bf5668..ea98433 100644 (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);
 
index 76f3716..2039c1b 100644 (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]);
 
@@ -452,6 +560,73 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff,
 }
 
 /**
+ * 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
  * @callback: [in] pull callback
index c0aef7e..6b90abf 100644 (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");
index fd455f7..0cfe7f9 100644 (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,8 +1102,24 @@ 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);
-
-                       /* remove the handle from the database */
-                       ipa3_id_remove(id);
+                       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);
+                       }
                }
 
                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)) {
index 74176d1..f4bce29 100644 (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;
index a4b817c..623d0f0 100644 (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;
 }
index 001ef39..33090dd 100644 (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
  */