summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c46
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c68
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h171
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_rt.c80
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c497
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c125
-rw-r--r--include/uapi/linux/msm_ipa.h111
-rw-r--r--include/uapi/linux/rmnet_ipa_fd_ioctl.h80
11 files changed, 1112 insertions, 77 deletions
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index 4275e3d26157..10fd721b8f69 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -86,7 +86,9 @@ const char *ipa_event_name[] = {
__stringify(ADD_VLAN_IFACE),
__stringify(DEL_VLAN_IFACE),
__stringify(ADD_L2TP_VLAN_MAPPING),
- __stringify(DEL_L2TP_VLAN_MAPPING)
+ __stringify(DEL_L2TP_VLAN_MAPPING),
+ __stringify(IPA_PER_CLIENT_STATS_CONNECT_EVENT),
+ __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT),
};
const char *ipa_hdr_l2_type_name[] = {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index fd503f48f17c..73321df80ada 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -992,8 +992,52 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
break;
}
break;
+
+ case IPA_IOC_ADD_RT_RULE_EXT:
+ if (copy_from_user(header,
+ (const void __user *)arg,
+ sizeof(struct ipa_ioc_add_rt_rule_ext))) {
+ retval = -EFAULT;
+ break;
+ }
+ pre_entry =
+ ((struct ipa_ioc_add_rt_rule_ext *)header)->num_rules;
+ pyld_sz =
+ sizeof(struct ipa_ioc_add_rt_rule_ext) +
+ pre_entry * sizeof(struct ipa_rt_rule_add_ext);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (const void __user *)arg,
+ pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ /* add check in case user-space module compromised */
+ if (unlikely(
+ ((struct ipa_ioc_add_rt_rule_ext *)param)->num_rules
+ != pre_entry)) {
+ IPAERR(" prevent memory corruption(%d not match %d)\n",
+ ((struct ipa_ioc_add_rt_rule_ext *)param)->
+ num_rules,
+ pre_entry);
+ retval = -EINVAL;
+ break;
+ }
+ if (ipa3_add_rt_rule_ext(
+ (struct ipa_ioc_add_rt_rule_ext *)param)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (copy_to_user((void __user *)arg, param, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
case IPA_IOC_ADD_RT_RULE_AFTER:
- if (copy_from_user(header, (u8 *)arg,
+ if (copy_from_user(header, (const void __user *)arg,
sizeof(struct ipa_ioc_add_rt_rule_after))) {
retval = -EFAULT;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index c7ab616cb5b8..8f7beef22b84 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -67,7 +67,9 @@ const char *ipa3_event_name[] = {
__stringify(ADD_VLAN_IFACE),
__stringify(DEL_VLAN_IFACE),
__stringify(ADD_L2TP_VLAN_MAPPING),
- __stringify(DEL_L2TP_VLAN_MAPPING)
+ __stringify(DEL_L2TP_VLAN_MAPPING),
+ __stringify(IPA_PER_CLIENT_STATS_CONNECT_EVENT),
+ __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT),
};
const char *ipa3_hdr_l2_type_name[] = {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 5ff926a60129..89c7b66b98d6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -435,6 +435,7 @@ struct ipa3_rt_entry {
int id;
u16 prio;
u16 rule_id;
+ u16 rule_id_valid;
};
/**
@@ -1615,6 +1616,8 @@ 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_ext(struct ipa_ioc_add_rt_rule_ext *rules);
+
int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules);
int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index 571852c076ea..6f30c75ae7f6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -1363,6 +1363,74 @@ int ipa3_qmi_stop_data_qouta(void)
resp.resp.error, "ipa_stop_data_usage_quota_req_msg_v01");
}
+int ipa3_qmi_enable_per_client_stats(
+ struct ipa_enable_per_client_stats_req_msg_v01 *req,
+ struct ipa_enable_per_client_stats_resp_msg_v01 *resp)
+{
+ struct msg_desc req_desc, resp_desc;
+ int rc;
+
+ req_desc.max_msg_len =
+ QMI_IPA_ENABLE_PER_CLIENT_STATS_REQ_MAX_MSG_LEN_V01;
+ req_desc.msg_id =
+ QMI_IPA_ENABLE_PER_CLIENT_STATS_REQ_V01;
+ req_desc.ei_array =
+ ipa3_enable_per_client_stats_req_msg_data_v01_ei;
+
+ resp_desc.max_msg_len =
+ QMI_IPA_ENABLE_PER_CLIENT_STATS_RESP_MAX_MSG_LEN_V01;
+ resp_desc.msg_id =
+ QMI_IPA_ENABLE_PER_CLIENT_STATS_RESP_V01;
+ resp_desc.ei_array =
+ ipa3_enable_per_client_stats_resp_msg_data_v01_ei;
+
+ IPAWANDBG("Sending QMI_IPA_ENABLE_PER_CLIENT_STATS_REQ_V01\n");
+
+ rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req,
+ sizeof(struct ipa_enable_per_client_stats_req_msg_v01),
+ &resp_desc, resp,
+ sizeof(struct ipa_enable_per_client_stats_resp_msg_v01),
+ QMI_SEND_STATS_REQ_TIMEOUT_MS);
+
+ IPAWANDBG("QMI_IPA_ENABLE_PER_CLIENT_STATS_RESP_V01 received\n");
+
+ return ipa3_check_qmi_response(rc,
+ QMI_IPA_ENABLE_PER_CLIENT_STATS_REQ_V01, resp->resp.result,
+ resp->resp.error, "ipa3_qmi_enable_per_client_stats");
+}
+
+int ipa3_qmi_get_per_client_packet_stats(
+ struct ipa_get_stats_per_client_req_msg_v01 *req,
+ struct ipa_get_stats_per_client_resp_msg_v01 *resp)
+{
+ struct msg_desc req_desc, resp_desc;
+ int rc;
+
+ req_desc.max_msg_len = QMI_IPA_GET_STATS_PER_CLIENT_REQ_MAX_MSG_LEN_V01;
+ req_desc.msg_id = QMI_IPA_GET_STATS_PER_CLIENT_REQ_V01;
+ req_desc.ei_array = ipa3_get_stats_per_client_req_msg_data_v01_ei;
+
+ resp_desc.max_msg_len =
+ QMI_IPA_GET_STATS_PER_CLIENT_RESP_MAX_MSG_LEN_V01;
+ resp_desc.msg_id = QMI_IPA_GET_STATS_PER_CLIENT_RESP_V01;
+ resp_desc.ei_array = ipa3_get_stats_per_client_resp_msg_data_v01_ei;
+
+ IPAWANDBG("Sending QMI_IPA_GET_STATS_PER_CLIENT_REQ_V01\n");
+
+ rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req,
+ sizeof(struct ipa_get_stats_per_client_req_msg_v01),
+ &resp_desc, resp,
+ sizeof(struct ipa_get_stats_per_client_resp_msg_v01),
+ QMI_SEND_STATS_REQ_TIMEOUT_MS);
+
+ IPAWANDBG("QMI_IPA_GET_STATS_PER_CLIENT_RESP_V01 received\n");
+
+ return ipa3_check_qmi_response(rc,
+ QMI_IPA_GET_STATS_PER_CLIENT_REQ_V01, resp->resp.result,
+ resp->resp.error,
+ "struct ipa_get_stats_per_client_req_msg_v01");
+}
+
void ipa3_qmi_init(void)
{
mutex_init(&ipa3_qmi_lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
index e6f1e2ce0b75..a2af87d5da2b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
@@ -32,54 +32,58 @@
#define IPAWANDBG(fmt, args...) \
do { \
- pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \
+ pr_debug(DEV_NAME " %s:%d " fmt, __func__,\
+ __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
- DEV_NAME " %s:%d " fmt, ## args); \
+ DEV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
- DEV_NAME " %s:%d " fmt, ## args); \
+ DEV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPAWANDBG_LOW(fmt, args...) \
do { \
- pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \
+ pr_debug(DEV_NAME " %s:%d " fmt, __func__,\
+ __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
- DEV_NAME " %s:%d " fmt, ## args); \
+ DEV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPAWANERR(fmt, args...) \
do { \
- pr_err(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \
+ pr_err(DEV_NAME " %s:%d " fmt, __func__,\
+ __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
- DEV_NAME " %s:%d " fmt, ## args); \
+ DEV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
- DEV_NAME " %s:%d " fmt, ## args); \
+ DEV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPAWANINFO(fmt, args...) \
do { \
- pr_info(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args); \
+ pr_info(DEV_NAME " %s:%d " fmt, __func__,\
+ __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
- DEV_NAME " %s:%d " fmt, ## args); \
+ DEV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
- DEV_NAME " %s:%d " fmt, ## args); \
+ DEV_NAME " %s:%d " fmt, ## args); \
} while (0)
extern struct ipa3_qmi_context *ipa3_qmi_ctx;
struct ipa3_qmi_context {
-struct ipa_ioc_ext_intf_prop q6_ul_filter_rule[MAX_NUM_Q6_RULE];
-u32 q6_ul_filter_rule_hdl[MAX_NUM_Q6_RULE];
-int num_ipa_install_fltr_rule_req_msg;
-struct ipa_install_fltr_rule_req_msg_v01
+ struct ipa_ioc_ext_intf_prop q6_ul_filter_rule[MAX_NUM_Q6_RULE];
+ u32 q6_ul_filter_rule_hdl[MAX_NUM_Q6_RULE];
+ int num_ipa_install_fltr_rule_req_msg;
+ struct ipa_install_fltr_rule_req_msg_v01
ipa_install_fltr_rule_req_msg_cache[MAX_NUM_QMI_RULE_CACHE];
-int num_ipa_install_fltr_rule_req_ex_msg;
-struct ipa_install_fltr_rule_req_ex_msg_v01
+ int num_ipa_install_fltr_rule_req_ex_msg;
+ struct ipa_install_fltr_rule_req_ex_msg_v01
ipa_install_fltr_rule_req_ex_msg_cache[MAX_NUM_QMI_RULE_CACHE];
-int num_ipa_fltr_installed_notif_req_msg;
-struct ipa_fltr_installed_notif_req_msg_v01
+ int num_ipa_fltr_installed_notif_req_msg;
+ struct ipa_fltr_installed_notif_req_msg_v01
ipa_fltr_installed_notif_req_msg_cache[MAX_NUM_QMI_RULE_CACHE];
-bool modem_cfg_emb_pipe_flt;
+ bool modem_cfg_emb_pipe_flt;
};
struct ipa3_rmnet_mux_val {
@@ -95,56 +99,69 @@ extern struct elem_info ipa3_init_modem_driver_req_msg_data_v01_ei[];
extern struct elem_info ipa3_init_modem_driver_resp_msg_data_v01_ei[];
extern struct elem_info ipa3_indication_reg_req_msg_data_v01_ei[];
extern struct elem_info ipa3_indication_reg_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_master_driver_init_complt_ind_msg_data_v01_ei[];
+
+extern struct elem_info
+ ipa3_master_driver_init_complt_ind_msg_data_v01_ei[];
extern struct elem_info ipa3_install_fltr_rule_req_msg_data_v01_ei[];
extern struct elem_info ipa3_install_fltr_rule_resp_msg_data_v01_ei[];
extern struct elem_info ipa3_fltr_installed_notif_req_msg_data_v01_ei[];
extern struct elem_info ipa3_fltr_installed_notif_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_enable_force_clear_datapath_req_msg_data_v01_ei[];
-extern struct elem_info ipa3_enable_force_clear_datapath_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_disable_force_clear_datapath_req_msg_data_v01_ei[];
+
+extern struct elem_info
+ ipa3_enable_force_clear_datapath_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_enable_force_clear_datapath_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_disable_force_clear_datapath_req_msg_data_v01_ei[];
extern struct elem_info
ipa3_disable_force_clear_datapath_resp_msg_data_v01_ei[];
extern struct elem_info ipa3_config_req_msg_data_v01_ei[];
extern struct elem_info ipa3_config_resp_msg_data_v01_ei[];
extern struct elem_info ipa3_get_data_stats_req_msg_data_v01_ei[];
extern struct elem_info ipa3_get_data_stats_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_get_apn_data_stats_req_msg_data_v01_ei[];
-extern struct elem_info ipa3_get_apn_data_stats_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_set_data_usage_quota_req_msg_data_v01_ei[];
-extern struct elem_info ipa3_set_data_usage_quota_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_data_usage_quota_reached_ind_msg_data_v01_ei[];
-extern struct elem_info ipa3_stop_data_usage_quota_req_msg_data_v01_ei[];
-extern struct elem_info ipa3_stop_data_usage_quota_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_init_modem_driver_cmplt_req_msg_data_v01_ei[];
-extern struct elem_info ipa3_init_modem_driver_cmplt_resp_msg_data_v01_ei[];
-extern struct elem_info ipa3_install_fltr_rule_req_ex_msg_data_v01_ei[];
-extern struct elem_info ipa3_install_fltr_rule_resp_ex_msg_data_v01_ei[];
-
- extern struct elem_info
- ipa3_install_fltr_rule_req_ex_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_install_fltr_rule_resp_ex_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_ul_firewall_rule_type_data_v01_ei[];
- extern struct elem_info
- ipa3_ul_firewall_config_result_type_data_v01_ei[];
- extern struct elem_info
- ipa3_per_client_stats_info_type_data_v01_ei[];
- extern struct elem_info
- ipa3_enable_per_client_stats_req_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_enable_per_client_stats_resp_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_get_stats_per_client_req_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_get_stats_per_client_resp_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_configure_ul_firewall_rules_req_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_configure_ul_firewall_rules_resp_msg_data_v01_ei[];
- extern struct elem_info
- ipa3_configure_ul_firewall_rules_ind_msg_data_v01_ei[];
+
+extern struct elem_info
+ ipa3_get_apn_data_stats_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_get_apn_data_stats_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_set_data_usage_quota_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_set_data_usage_quota_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_data_usage_quota_reached_ind_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_stop_data_usage_quota_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_stop_data_usage_quota_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_init_modem_driver_cmplt_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_init_modem_driver_cmplt_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_install_fltr_rule_req_ex_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_install_fltr_rule_resp_ex_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_ul_firewall_rule_type_data_v01_ei[];
+extern struct elem_info
+ ipa3_ul_firewall_config_result_type_data_v01_ei[];
+extern struct elem_info
+ ipa3_per_client_stats_info_type_data_v01_ei[];
+extern struct elem_info
+ ipa3_enable_per_client_stats_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_enable_per_client_stats_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_get_stats_per_client_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_get_stats_per_client_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_configure_ul_firewall_rules_req_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_configure_ul_firewall_rules_resp_msg_data_v01_ei[];
+extern struct elem_info
+ ipa3_configure_ul_firewall_rules_ind_msg_data_v01_ei[];
/**
* struct ipa3_rmnet_context - IPA rmnet context
@@ -219,6 +236,16 @@ int rmnet_ipa3_query_tethering_stats_all(
struct wan_ioctl_query_tether_stats_all *data);
int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data);
+int rmnet_ipa3_set_lan_client_info(struct wan_ioctl_lan_client_info *data);
+
+int rmnet_ipa3_clear_lan_client_info(struct wan_ioctl_lan_client_info *data);
+
+int rmnet_ipa3_send_lan_client_msg(struct wan_ioctl_send_lan_client_msg *data);
+
+int rmnet_ipa3_enable_per_client_stats(bool *data);
+
+int rmnet_ipa3_query_per_client_stats(
+ struct wan_ioctl_query_per_client_stats *data);
int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req,
struct ipa_get_data_stats_resp_msg_v01 *resp);
@@ -232,6 +259,14 @@ int ipa3_qmi_stop_data_qouta(void);
void ipa3_q6_handshake_complete(bool ssr_bootup);
+int ipa3_qmi_enable_per_client_stats(
+ struct ipa_enable_per_client_stats_req_msg_v01 *req,
+ struct ipa_enable_per_client_stats_resp_msg_v01 *resp);
+
+int ipa3_qmi_get_per_client_packet_stats(
+ struct ipa_get_stats_per_client_req_msg_v01 *req,
+ struct ipa_get_stats_per_client_resp_msg_v01 *resp);
+
void ipa3_qmi_init(void);
void ipa3_qmi_cleanup(void);
@@ -348,12 +383,28 @@ static inline int ipa3_qmi_stop_data_qouta(void)
static inline void ipa3_q6_handshake_complete(bool ssr_bootup) { }
+static inline int ipa3_qmi_enable_per_client_stats(
+ struct ipa_enable_per_client_stats_req_msg_v01 *req,
+ struct ipa_enable_per_client_stats_resp_msg_v01 *resp)
+{
+ return -EPERM;
+}
+
+static inline int ipa3_qmi_get_per_client_packet_stats(
+ struct ipa_get_stats_per_client_req_msg_v01 *req,
+ struct ipa_get_stats_per_client_resp_msg_v01 *resp)
+{
+ return -EPERM;
+}
+
static inline void ipa3_qmi_init(void)
{
+
}
static inline void ipa3_qmi_cleanup(void)
{
+
}
#endif /* CONFIG_RMNET_IPA3 */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index ff57e3bd48f0..bc75ba912e0d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -918,7 +918,8 @@ static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule,
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)
+ struct ipa3_hdr_proc_ctx_entry *proc_ctx,
+ u16 rule_id)
{
int id;
@@ -933,11 +934,16 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry,
(*(entry))->tbl = tbl;
(*(entry))->hdr = hdr;
(*(entry))->proc_ctx = proc_ctx;
- id = ipa3_alloc_rule_id(&tbl->rule_ids);
- if (id < 0) {
- IPAERR("failed to allocate rule id\n");
- WARN_ON(1);
- goto alloc_rule_id_fail;
+ if (rule_id) {
+ id = rule_id;
+ (*(entry))->rule_id_valid = 1;
+ } else {
+ id = ipa3_alloc_rule_id(&tbl->rule_ids);
+ if (id < 0) {
+ IPAERR("failed to allocate rule id\n");
+ WARN_ON(1);
+ goto alloc_rule_id_fail;
+ }
}
(*(entry))->rule_id = id;
@@ -984,7 +990,8 @@ 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)
+ const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl,
+ u16 rule_id)
{
struct ipa3_rt_tbl *tbl;
struct ipa3_rt_entry *entry;
@@ -1012,7 +1019,8 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
goto error;
}
- if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx))
+ if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx,
+ rule_id))
goto error;
if (at_rear)
@@ -1043,7 +1051,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))
+ if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx, 0))
goto error;
list_add(&entry->link, &((*add_after_entry)->link));
@@ -1087,8 +1095,54 @@ int ipa3_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)) {
- IPAERR_RL("failed to add rt rule %d\n", i);
+ &rules->rules[i].rt_rule_hdl,
+ 0)) {
+ IPAERR("failed to add rt rule %d\n", i);
+ rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
+ } else {
+ rules->rules[i].status = 0;
+ }
+ }
+
+ if (rules->commit)
+ if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) {
+ ret = -EPERM;
+ goto bail;
+ }
+
+ ret = 0;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return ret;
+}
+
+/**
+ * ipa3_add_rt_rule_ext() - Add the specified routing rules to SW with rule id
+ * and optionally commit to IPA HW
+ * @rules: [inout] set of routing rules to add
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa3_add_rt_rule_ext(struct ipa_ioc_add_rt_rule_ext *rules)
+{
+ int i;
+ int ret;
+
+ if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
+ IPAERR("bad parm\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&ipa3_ctx->lock);
+ for (i = 0; i < rules->num_rules; i++) {
+ 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].rule_id)) {
+ IPAERR("failed to add rt rule %d\n", i);
rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
} else {
rules->rules[i].status = 0;
@@ -1229,7 +1283,9 @@ int __ipa3_del_rt_rule(u32 rule_hdl)
IPADBG("del rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n ref_cnt=%u",
entry->tbl->idx, entry->tbl->rule_cnt,
entry->rule_id, entry->tbl->ref_cnt);
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ /* if rule id was allocated from idr, remove it */
+ if (!entry->rule_id_valid)
+ idr_remove(&entry->tbl->rule_ids, entry->rule_id);
if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) {
if (__ipa_del_rt_tbl(entry->tbl))
IPAERR_RL("fail to del RT tbl\n");
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 8fbde6675070..5e9db61bdca3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -142,6 +142,10 @@ struct rmnet_ipa3_context {
u32 ipa3_to_apps_hdl;
struct mutex pipe_handle_guard;
struct mutex add_mux_channel_lock;
+ struct mutex per_client_stats_guard;
+ struct ipa_tether_device_info
+ tether_device
+ [IPACM_MAX_CLIENT_DEVICE_TYPES];
};
static struct rmnet_ipa3_context *rmnet_ipa3_ctx;
@@ -2571,7 +2575,9 @@ static void rmnet_ipa_free_msg(void *buff, u32 len, u32 type)
}
if (type != IPA_TETHERING_STATS_UPDATE_STATS &&
- type != IPA_TETHERING_STATS_UPDATE_NETWORK_STATS) {
+ type != IPA_TETHERING_STATS_UPDATE_NETWORK_STATS &&
+ type != IPA_PER_CLIENT_STATS_CONNECT_EVENT &&
+ type != IPA_PER_CLIENT_STATS_DISCONNECT_EVENT) {
IPAWANERR("Wrong type given. buff %p type %d\n",
buff, type);
}
@@ -3317,8 +3323,488 @@ void ipa3_q6_handshake_complete(bool ssr_bootup)
}
}
+static inline bool rmnet_ipa3_check_any_client_inited
+(
+ enum ipacm_per_client_device_type device_type
+)
+{
+ int i = 0;
+
+ for (; i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++) {
+ if (rmnet_ipa3_ctx->tether_device[device_type].
+ lan_client[i].client_idx != -1 &&
+ rmnet_ipa3_ctx->tether_device[device_type].
+ lan_client[i].inited) {
+ IPAWANERR("Found client index: %d which is inited\n",
+ i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static inline int rmnet_ipa3_get_lan_client_info
+(
+ enum ipacm_per_client_device_type device_type,
+ uint8_t mac[]
+)
+{
+ int i = 0;
+
+ IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+
+ for (; i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++) {
+ if (memcmp(
+ rmnet_ipa3_ctx->tether_device[device_type].
+ lan_client[i].mac,
+ mac,
+ IPA_MAC_ADDR_SIZE) == 0) {
+ IPAWANDBG("Matched client index: %d\n", i);
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static inline int rmnet_ipa3_delete_lan_client_info
+(
+ enum ipacm_per_client_device_type device_type,
+ int lan_clnt_idx
+)
+{
+ struct ipa_lan_client *lan_client = NULL;
+ int i;
+
+ /* Check if the request is to clean up all clients. */
+ if (lan_clnt_idx == 0xffffffff) {
+ /* Reset the complete device info. */
+ memset(&rmnet_ipa3_ctx->tether_device[device_type], 0,
+ sizeof(struct ipa_tether_device_info));
+ rmnet_ipa3_ctx->tether_device[device_type].ul_src_pipe = -1;
+ for (i = 0; i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++)
+ rmnet_ipa3_ctx->tether_device[device_type].
+ lan_client[i].client_idx = -1;
+ } else {
+ lan_client =
+ &rmnet_ipa3_ctx->tether_device[device_type].
+ lan_client[lan_clnt_idx];
+ /* Reset the client info before sending the message. */
+ memset(lan_client, 0, sizeof(struct ipa_lan_client));
+ lan_client->client_idx = -1;
+
+ }
+ return 0;
+}
+
+/* rmnet_ipa3_set_lan_client_info() -
+ * @data - IOCTL data
+ *
+ * This function handles WAN_IOC_SET_LAN_CLIENT_INFO.
+ * It is used to store LAN client information which
+ * is used to fetch the packet stats for a client.
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: Invalid args provided
+ */
+int rmnet_ipa3_set_lan_client_info(
+ struct wan_ioctl_lan_client_info *data)
+{
+
+ struct ipa_lan_client *lan_client = NULL;
+
+
+ IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac[0], data->mac[1], data->mac[2],
+ data->mac[3], data->mac[4], data->mac[5]);
+
+ /* Check if Device type is valid. */
+ if (data->device_type >= IPACM_MAX_CLIENT_DEVICE_TYPES ||
+ data->device_type < 0) {
+ IPAWANERR("Invalid Device type: %d\n", data->device_type);
+ return -EINVAL;
+ }
+
+ /* Check if Client index is valid. */
+ if (data->client_idx >= IPA_MAX_NUM_HW_PATH_CLIENTS ||
+ data->client_idx < 0) {
+ IPAWANERR("Invalid Client Index: %d\n", data->client_idx);
+ return -EINVAL;
+ }
+
+ mutex_lock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ if (data->client_init) {
+ /* check if the client is already inited. */
+ if (rmnet_ipa3_ctx->tether_device[data->device_type]
+ .lan_client[data->client_idx].inited) {
+ IPAWANERR("Client already inited: %d:%d\n",
+ data->device_type, data->client_idx);
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ return -EINVAL;
+ }
+ }
+
+ lan_client =
+ &rmnet_ipa3_ctx->tether_device[data->device_type].
+ lan_client[data->client_idx];
+
+ memcpy(lan_client->mac, data->mac, IPA_MAC_ADDR_SIZE);
+
+ lan_client->client_idx = data->client_idx;
+
+ /* Update the Source pipe. */
+ rmnet_ipa3_ctx->tether_device[data->device_type].ul_src_pipe =
+ ipa3_get_ep_mapping(data->ul_src_pipe);
+
+ /* Update the header length if not set. */
+ if (!rmnet_ipa3_ctx->tether_device[data->device_type].hdr_len)
+ rmnet_ipa3_ctx->tether_device[data->device_type].hdr_len =
+ data->hdr_len;
+
+ lan_client->inited = true;
+
+ rmnet_ipa3_ctx->tether_device[data->device_type].num_clients++;
+
+ IPAWANDBG("Set the lan client info: %d, %d, %d\n",
+ lan_client->client_idx,
+ rmnet_ipa3_ctx->tether_device[data->device_type].ul_src_pipe,
+ rmnet_ipa3_ctx->tether_device[data->device_type].num_clients);
+
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+
+ return 0;
+}
+
+/* rmnet_ipa3_delete_lan_client_info() -
+ * @data - IOCTL data
+ *
+ * This function handles WAN_IOC_DELETE_LAN_CLIENT_INFO.
+ * It is used to delete LAN client information which
+ * is used to fetch the packet stats for a client.
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: Invalid args provided
+ */
+int rmnet_ipa3_clear_lan_client_info(
+ struct wan_ioctl_lan_client_info *data)
+{
+
+ struct ipa_lan_client *lan_client = NULL;
+
+
+ IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac[0], data->mac[1], data->mac[2],
+ data->mac[3], data->mac[4], data->mac[5]);
+
+ /* Check if Device type is valid. */
+ if (data->device_type >= IPACM_MAX_CLIENT_DEVICE_TYPES ||
+ data->device_type < 0) {
+ IPAWANERR("Invalid Device type: %d\n", data->device_type);
+ return -EINVAL;
+ }
+
+ /* Check if Client index is valid. */
+ if (data->client_idx >= IPA_MAX_NUM_HW_PATH_CLIENTS ||
+ data->client_idx < 0) {
+ IPAWANERR("Invalid Client Index: %d\n", data->client_idx);
+ return -EINVAL;
+ }
+
+ mutex_lock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ lan_client =
+ &rmnet_ipa3_ctx->tether_device[data->device_type].
+ lan_client[data->client_idx];
+
+ if (!data->client_init) {
+ /* check if the client is already de-inited. */
+ if (!lan_client->inited) {
+ IPAWANERR("Client already de-inited: %d:%d\n",
+ data->device_type, data->client_idx);
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ return -EINVAL;
+ }
+ }
+
+ lan_client->inited = false;
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+
+ return 0;
+}
+
+
+/* rmnet_ipa3_send_lan_client_msg() -
+ * @data - IOCTL data
+ *
+ * This function handles WAN_IOC_SEND_LAN_CLIENT_MSG.
+ * It is used to send LAN client information to IPACM.
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: Invalid args provided
+ */
+int rmnet_ipa3_send_lan_client_msg(
+ struct wan_ioctl_send_lan_client_msg *data)
+{
+ struct ipa_msg_meta msg_meta;
+ int rc;
+ struct ipa_lan_client_msg *lan_client;
+
+ /* Notify IPACM to reset the client index. */
+ lan_client = kzalloc(sizeof(struct ipa_lan_client_msg),
+ GFP_KERNEL);
+ if (!lan_client) {
+ IPAWANERR("Can't allocate memory for tether_info\n");
+ return -ENOMEM;
+ }
+ memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
+ memcpy(lan_client, &data->lan_client,
+ sizeof(struct ipa_lan_client_msg));
+ msg_meta.msg_type = data->client_event;
+ msg_meta.msg_len = sizeof(struct ipa_lan_client_msg);
+
+ rc = ipa_send_msg(&msg_meta, lan_client, rmnet_ipa_free_msg);
+ if (rc) {
+ IPAWANERR("ipa_send_msg failed: %d\n", rc);
+ kfree(lan_client);
+ return rc;
+ }
+ return 0;
+}
+
+/* rmnet_ipa3_enable_per_client_stats() -
+ * @data - IOCTL data
+ *
+ * This function handles WAN_IOC_ENABLE_PER_CLIENT_STATS.
+ * It is used to indicate Q6 to start capturing per client stats.
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: Invalid args provided
+ */
+int rmnet_ipa3_enable_per_client_stats(
+ bool *data)
+{
+ struct ipa_enable_per_client_stats_req_msg_v01 *req;
+ struct ipa_enable_per_client_stats_resp_msg_v01 *resp;
+ int rc;
+
+ req =
+ kzalloc(sizeof(struct ipa_enable_per_client_stats_req_msg_v01),
+ GFP_KERNEL);
+ if (!req) {
+ IPAWANERR("Can't allocate memory for stats message\n");
+ return -ENOMEM;
+ }
+ resp =
+ kzalloc(sizeof(struct ipa_enable_per_client_stats_resp_msg_v01),
+ GFP_KERNEL);
+ if (!resp) {
+ IPAWANERR("Can't allocate memory for stats message\n");
+ kfree(req);
+ return -ENOMEM;
+ }
+ memset(req, 0,
+ sizeof(struct ipa_enable_per_client_stats_req_msg_v01));
+ memset(resp, 0,
+ sizeof(struct ipa_enable_per_client_stats_resp_msg_v01));
+
+ if (*data)
+ req->enable_per_client_stats = 1;
+ else
+ req->enable_per_client_stats = 0;
+
+ rc = ipa3_qmi_enable_per_client_stats(req, resp);
+ if (rc) {
+ IPAWANERR("can't enable per client stats\n");
+ kfree(req);
+ kfree(resp);
+ return rc;
+ }
+
+ kfree(req);
+ kfree(resp);
+ return 0;
+}
+
+int rmnet_ipa3_query_per_client_stats(
+ struct wan_ioctl_query_per_client_stats *data)
+{
+ struct ipa_get_stats_per_client_req_msg_v01 *req;
+ struct ipa_get_stats_per_client_resp_msg_v01 *resp;
+ int rc, lan_clnt_idx, lan_clnt_idx1, i;
+ struct ipa_lan_client *lan_client = NULL;
+
+
+ IPAWANDBG("Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->client_info[0].mac[0],
+ data->client_info[0].mac[1],
+ data->client_info[0].mac[2],
+ data->client_info[0].mac[3],
+ data->client_info[0].mac[4],
+ data->client_info[0].mac[5]);
+
+ /* Check if Device type is valid. */
+ if (data->device_type >= IPACM_MAX_CLIENT_DEVICE_TYPES ||
+ data->device_type < 0) {
+ IPAWANERR("Invalid Device type: %d\n", data->device_type);
+ return -EINVAL;
+ }
+
+ /* Check if num_clients is valid. */
+ if (data->num_clients != IPA_MAX_NUM_HW_PATH_CLIENTS &&
+ data->num_clients != 1) {
+ IPAWANERR("Invalid number of clients: %d\n", data->num_clients);
+ return -EINVAL;
+ }
+
+ mutex_lock(&rmnet_ipa3_ctx->per_client_stats_guard);
+
+ if (data->num_clients == 1) {
+ /* Check if the client info is valid.*/
+ lan_clnt_idx1 = rmnet_ipa3_get_lan_client_info(
+ data->device_type,
+ data->client_info[0].mac);
+ if (lan_clnt_idx1 < 0) {
+ IPAWANERR("Client info not available return.\n");
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ return -EINVAL;
+ }
+ lan_client =
+ &rmnet_ipa3_ctx->tether_device[data->device_type].
+ lan_client[lan_clnt_idx1];
+ /*
+ * Check if disconnect flag is set and
+ * see if all the clients info are cleared.
+ */
+ if (data->disconnect_clnt &&
+ lan_client->inited) {
+ IPAWANERR("Client not inited. Try again.\n");
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ return -EAGAIN;
+ }
+
+ } else {
+ /* Max number of clients. */
+ /* Check if disconnect flag is set and
+ * see if all the clients info are cleared.
+ */
+ if (data->disconnect_clnt &&
+ rmnet_ipa3_check_any_client_inited(data->device_type)) {
+ IPAWANERR("CLient not inited. Try again.\n");
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ return -EAGAIN;
+ }
+ lan_clnt_idx1 = 0xffffffff;
+ }
+
+ req = kzalloc(sizeof(struct ipa_get_stats_per_client_req_msg_v01),
+ GFP_KERNEL);
+ if (!req) {
+ IPAWANERR("Can't allocate memory for stats message\n");
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ return -ENOMEM;
+ }
+ resp = kzalloc(sizeof(struct ipa_get_stats_per_client_resp_msg_v01),
+ GFP_KERNEL);
+ if (!resp) {
+ IPAWANERR("Can't allocate memory for stats message\n");
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ kfree(req);
+ return -ENOMEM;
+ }
+ memset(req, 0, sizeof(struct ipa_get_stats_per_client_req_msg_v01));
+ memset(resp, 0, sizeof(struct ipa_get_stats_per_client_resp_msg_v01));
+
+ if (data->reset_stats) {
+ req->reset_stats_valid = true;
+ req->reset_stats = true;
+ IPAWANDBG("fetch and reset the client stats\n");
+ }
+
+ req->client_id = lan_clnt_idx1;
+ req->src_pipe_id =
+ rmnet_ipa3_ctx->tether_device[data->device_type].ul_src_pipe;
+
+ IPAWANDBG("fetch the client stats for %d, %d\n", req->client_id,
+ req->src_pipe_id);
+
+ rc = ipa3_qmi_get_per_client_packet_stats(req, resp);
+ if (rc) {
+ IPAWANERR("can't get per client stats\n");
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ kfree(req);
+ kfree(resp);
+ return rc;
+ }
+
+ if (resp->per_client_stats_list_valid) {
+ for (i = 0; i < resp->per_client_stats_list_len
+ && i < IPA_MAX_NUM_HW_PATH_CLIENTS; i++) {
+ /* Subtract the header bytes from the DL bytes. */
+ data->client_info[i].ipv4_rx_bytes =
+ (resp->per_client_stats_list[i].num_dl_ipv4_bytes) -
+ (rmnet_ipa3_ctx->
+ tether_device[data->device_type].hdr_len *
+ resp->per_client_stats_list[i].num_dl_ipv4_pkts);
+ /* UL header bytes are subtracted by Q6. */
+ data->client_info[i].ipv4_tx_bytes =
+ resp->per_client_stats_list[i].num_ul_ipv4_bytes;
+ /* Subtract the header bytes from the DL bytes. */
+ data->client_info[i].ipv6_rx_bytes =
+ (resp->per_client_stats_list[i].num_dl_ipv6_bytes) -
+ (rmnet_ipa3_ctx->
+ tether_device[data->device_type].hdr_len *
+ resp->per_client_stats_list[i].num_dl_ipv6_pkts);
+ /* UL header bytes are subtracted by Q6. */
+ data->client_info[i].ipv6_tx_bytes =
+ resp->per_client_stats_list[i].num_ul_ipv6_bytes;
+
+ IPAWANDBG("tx_b_v4(%lu)v6(%lu)rx_b_v4(%lu) v6(%lu)\n",
+ (unsigned long int) data->client_info[i].ipv4_tx_bytes,
+ (unsigned long int) data->client_info[i].ipv6_tx_bytes,
+ (unsigned long int) data->client_info[i].ipv4_rx_bytes,
+ (unsigned long int) data->client_info[i].ipv6_rx_bytes);
+
+ /* Get the lan client index. */
+ lan_clnt_idx = resp->per_client_stats_list[i].client_id;
+ /* Check if lan_clnt_idx is valid. */
+ if (lan_clnt_idx < 0 ||
+ lan_clnt_idx >= IPA_MAX_NUM_HW_PATH_CLIENTS) {
+ IPAWANERR("Lan client index not valid.\n");
+ mutex_unlock(
+ &rmnet_ipa3_ctx->per_client_stats_guard);
+ kfree(req);
+ kfree(resp);
+ ipa_assert();
+ return -EINVAL;
+ }
+ memcpy(data->client_info[i].mac,
+ rmnet_ipa3_ctx->
+ tether_device[data->device_type].
+ lan_client[lan_clnt_idx].mac,
+ IPA_MAC_ADDR_SIZE);
+ }
+ }
+
+ if (data->disconnect_clnt) {
+ rmnet_ipa3_delete_lan_client_info(data->device_type,
+ lan_clnt_idx1);
+ }
+
+ mutex_unlock(&rmnet_ipa3_ctx->per_client_stats_guard);
+ kfree(req);
+ kfree(resp);
+ return 0;
+}
+
static int __init ipa3_wwan_init(void)
{
+ int i, j;
rmnet_ipa3_ctx = kzalloc(sizeof(*rmnet_ipa3_ctx), GFP_KERNEL);
if (!rmnet_ipa3_ctx) {
IPAWANERR("no memory\n");
@@ -3330,6 +3816,14 @@ static int __init ipa3_wwan_init(void)
mutex_init(&rmnet_ipa3_ctx->pipe_handle_guard);
mutex_init(&rmnet_ipa3_ctx->add_mux_channel_lock);
+ mutex_init(&rmnet_ipa3_ctx->per_client_stats_guard);
+ /* Reset the Lan Stats. */
+ for (i = 0; i < IPACM_MAX_CLIENT_DEVICE_TYPES; i++) {
+ rmnet_ipa3_ctx->tether_device[i].ul_src_pipe = -1;
+ for (j = 0; j < IPA_MAX_NUM_HW_PATH_CLIENTS; j++)
+ rmnet_ipa3_ctx->tether_device[i].
+ lan_client[j].client_idx = -1;
+ }
rmnet_ipa3_ctx->ipa3_to_apps_hdl = -1;
rmnet_ipa3_ctx->apps_to_ipa3_hdl = -1;
@@ -3352,6 +3846,7 @@ static void __exit ipa3_wwan_cleanup(void)
ipa3_qmi_cleanup();
mutex_destroy(&rmnet_ipa3_ctx->pipe_handle_guard);
mutex_destroy(&rmnet_ipa3_ctx->add_mux_channel_lock);
+ mutex_destroy(&rmnet_ipa3_ctx->per_client_stats_guard);
ret = subsys_notif_unregister_notifier(
rmnet_ipa3_ctx->subsys_notify_handle, &ipa3_ssr_notifier);
if (ret)
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
index 51bbec464e4d..4010b50888e8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
@@ -50,6 +50,15 @@
#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
compat_uptr_t)
+#define WAN_IOCTL_ENABLE_PER_CLIENT_STATS32 _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_ENABLE_PER_CLIENT_STATS, \
+ compat_uptr_t)
+#define WAN_IOCTL_QUERY_PER_CLIENT_STATS32 _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_QUERY_PER_CLIENT_STATS, \
+ compat_uptr_t)
+#define WAN_IOCTL_SET_LAN_CLIENT_INFO32 _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_SET_LAN_CLIENT_INFO, \
+ compat_uptr_t)
#endif
static unsigned int dev_num = 1;
@@ -316,6 +325,122 @@ static long ipa3_wan_ioctl(struct file *filp,
}
break;
+ case WAN_IOC_ENABLE_PER_CLIENT_STATS:
+ IPAWANDBG_LOW("got WAN_IOC_ENABLE_PER_CLIENT_STATS :>>>\n");
+ pyld_sz = sizeof(bool);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (const void __user *)arg,
+ pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (rmnet_ipa3_enable_per_client_stats(
+ (bool *)param)) {
+ IPAWANERR("WAN_IOC_ENABLE_PER_CLIENT_STATS failed\n");
+ retval = -EFAULT;
+ break;
+ }
+
+ break;
+
+ case WAN_IOC_QUERY_PER_CLIENT_STATS:
+ IPAWANDBG_LOW("got WAN_IOC_QUERY_PER_CLIENT_STATS :>>>\n");
+ pyld_sz = sizeof(struct wan_ioctl_query_per_client_stats);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (const void __user *)arg,
+ pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+
+ retval = rmnet_ipa3_query_per_client_stats(
+ (struct wan_ioctl_query_per_client_stats *)param);
+ if (retval) {
+ IPAWANERR("WAN_IOC_QUERY_PER_CLIENT_STATS failed\n");
+ break;
+ }
+
+ if (copy_to_user((void __user *)arg, param, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case WAN_IOC_SET_LAN_CLIENT_INFO:
+ IPAWANDBG_LOW("got WAN_IOC_SET_LAN_CLIENT_INFO :>>>\n");
+ pyld_sz = sizeof(struct wan_ioctl_lan_client_info);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (const void __user *)arg,
+ pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (rmnet_ipa3_set_lan_client_info(
+ (struct wan_ioctl_lan_client_info *)param)) {
+ IPAWANERR("WAN_IOC_SET_LAN_CLIENT_INFO failed\n");
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case WAN_IOC_CLEAR_LAN_CLIENT_INFO:
+ IPAWANDBG_LOW("got WAN_IOC_CLEAR_LAN_CLIENT_INFO :>>>\n");
+ pyld_sz = sizeof(struct wan_ioctl_lan_client_info);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (const void __user *)arg,
+ pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (rmnet_ipa3_clear_lan_client_info(
+ (struct wan_ioctl_lan_client_info *)param)) {
+ IPAWANERR("WAN_IOC_CLEAR_LAN_CLIENT_INFO failed\n");
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+
+ case WAN_IOC_SEND_LAN_CLIENT_MSG:
+ IPAWANDBG_LOW("got WAN_IOC_SEND_LAN_CLIENT_MSG :>>>\n");
+ pyld_sz = sizeof(struct wan_ioctl_send_lan_client_msg);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (const void __user *)arg,
+ pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (rmnet_ipa3_send_lan_client_msg(
+ (struct wan_ioctl_send_lan_client_msg *)
+ param)) {
+ IPAWANERR("IOC_SEND_LAN_CLIENT_MSG failed\n");
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+
default:
retval = -ENOTTY;
}
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 322fb09b8614..0bdfc9741d19 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -128,6 +128,17 @@
#define IPA_WAN_MSG_IPv6_ADDR_GW_LEN 4
/**
+ * max number of lan clients supported per device type
+ * for LAN stats via HW.
+ */
+#define IPA_MAX_NUM_HW_PATH_CLIENTS 16
+
+/**
+ * max number of destination pipes possible for a client.
+ */
+#define QMI_IPA_MAX_CLIENT_DST_PIPES 4
+
+/**
* the attributes of the rule (routing or filtering)
*/
#define IPA_FLT_TOS (1ul << 0)
@@ -447,7 +458,14 @@ enum ipa_vlan_l2tp_event {
IPA_VLAN_L2TP_EVENT_MAX,
};
-#define IPA_EVENT_MAX_NUM (IPA_VLAN_L2TP_EVENT_MAX)
+enum ipa_per_client_stats_event {
+ IPA_PER_CLIENT_STATS_CONNECT_EVENT = IPA_VLAN_L2TP_EVENT_MAX,
+ IPA_PER_CLIENT_STATS_DISCONNECT_EVENT,
+ IPA_PER_CLIENT_STATS_EVENT_MAX,
+ IPA_EVENT_MAX_NUM = IPA_PER_CLIENT_STATS_EVENT_MAX,
+};
+
+#define IPA_EVENT_MAX_NUM ((int)IPA_PER_CLIENT_STATS_EVENT_MAX)
#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM)
/**
@@ -1061,6 +1079,48 @@ struct ipa_rt_rule_del {
};
/**
+ * struct ipa_rt_rule_add_ext - routing rule descriptor includes in
+ * and out parameters
+ * @rule: actual rule to be added
+ * @at_rear: add at back of routing table, it is NOT possible to add rules at
+ * the rear of the "default" routing tables
+ * @rt_rule_hdl: output parameter, handle to rule, valid when status is 0
+ * @status: output parameter, status of routing rule add operation,
+ * @rule_id: rule_id to be assigned to the routing rule. In case client
+ * specifies rule_id as 0 the driver will assign a new rule_id
+ * 0 for success,
+ * -1 for failure
+ */
+struct ipa_rt_rule_add_ext {
+ struct ipa_rt_rule rule;
+ uint8_t at_rear;
+ uint32_t rt_rule_hdl;
+ int status;
+ uint16_t rule_id;
+};
+
+/**
+ * struct ipa_ioc_add_rt_rule - routing rule addition parameters (supports
+ * multiple rules and commit with rule_id);
+ *
+ * all rules MUST be added to same table
+ * @commit: should rules be written to IPA HW also?
+ * @ip: IP family of rule
+ * @rt_tbl_name: name of routing table resource
+ * @num_rules: number of routing rules that follow
+ * @ipa_rt_rule_add_ext rules: all rules need to go back to back here,
+ * no pointers
+ */
+struct ipa_ioc_add_rt_rule_ext {
+ uint8_t commit;
+ enum ipa_ip_type ip;
+ char rt_tbl_name[IPA_RESOURCE_NAME_MAX];
+ uint8_t num_rules;
+ struct ipa_rt_rule_add_ext rules[0];
+};
+
+
+/**
* struct ipa_ioc_del_rt_rule - routing rule deletion parameters (supports
* multiple headers and commit)
* @commit: should rules be removed from IPA HW also?
@@ -1619,6 +1679,52 @@ enum ipacm_client_enum {
IPACM_CLIENT_WLAN,
IPACM_CLIENT_MAX
};
+
+enum ipacm_per_client_device_type {
+ IPACM_CLIENT_DEVICE_TYPE_USB = 0,
+ IPACM_CLIENT_DEVICE_TYPE_WLAN = 1,
+ IPACM_CLIENT_DEVICE_TYPE_ETH = 2
+};
+
+/**
+ * max number of device types supported.
+ */
+#define IPACM_MAX_CLIENT_DEVICE_TYPES 3
+
+/**
+ * @lanIface - Name of the lan interface
+ * @mac: Mac address of the client.
+ */
+struct ipa_lan_client_msg {
+ char lanIface[IPA_RESOURCE_NAME_MAX];
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+};
+
+/**
+ * struct ipa_lan_client - lan client data
+ * @mac: MAC Address of the client.
+ * @client_idx: Client Index.
+ * @inited: Bool to indicate whether client info is set.
+ */
+struct ipa_lan_client {
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+ int8_t client_idx;
+ uint8_t inited;
+};
+
+/**
+ * struct ipa_tether_device_info - tether device info indicated from IPACM
+ * @ul_src_pipe: Source pipe of the lan client.
+ * @hdr_len: Header length of the client.
+ * @num_clients: Number of clients connected.
+ */
+struct ipa_tether_device_info {
+ int32_t ul_src_pipe;
+ uint8_t hdr_len;
+ uint32_t num_clients;
+ struct ipa_lan_client lan_client[IPA_MAX_NUM_HW_PATH_CLIENTS];
+};
+
/**
* actual IOCTLs supported by IPA driver
*/
@@ -1631,6 +1737,9 @@ enum ipacm_client_enum {
#define IPA_IOC_ADD_RT_RULE _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_ADD_RT_RULE, \
struct ipa_ioc_add_rt_rule *)
+#define IPA_IOC_ADD_RT_RULE_EXT _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_ADD_RT_RULE_EXT, \
+ struct ipa_ioc_add_rt_rule_ext *)
#define IPA_IOC_ADD_RT_RULE_AFTER _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_ADD_RT_RULE_AFTER, \
struct ipa_ioc_add_rt_rule_after *)
diff --git a/include/uapi/linux/rmnet_ipa_fd_ioctl.h b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
index f04ac495a5c0..13dac9a1526d 100644
--- a/include/uapi/linux/rmnet_ipa_fd_ioctl.h
+++ b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
@@ -33,6 +33,12 @@
#define WAN_IOCTL_QUERY_DL_FILTER_STATS 8
#define WAN_IOCTL_ADD_FLT_RULE_EX 9
#define WAN_IOCTL_QUERY_TETHER_STATS_ALL 10
+#define WAN_IOCTL_ADD_UL_FLT_RULE 11
+#define WAN_IOCTL_ENABLE_PER_CLIENT_STATS 12
+#define WAN_IOCTL_QUERY_PER_CLIENT_STATS 13
+#define WAN_IOCTL_SET_LAN_CLIENT_INFO 14
+#define WAN_IOCTL_CLEAR_LAN_CLIENT_INFO 15
+#define WAN_IOCTL_SEND_LAN_CLIENT_MSG 16
/* User space may not have this defined. */
#ifndef IFNAMSIZ
@@ -126,6 +132,57 @@ struct wan_ioctl_query_dl_filter_stats {
uint32_t index;
};
+struct wan_ioctl_send_lan_client_msg {
+ /* Lan client info. */
+ struct ipa_lan_client_msg lan_client;
+ /* Event to indicate whether client is
+ * connected or disconnected.
+ */
+ enum ipa_per_client_stats_event client_event;
+};
+
+struct wan_ioctl_lan_client_info {
+ /* Device type of the client. */
+ enum ipacm_per_client_device_type device_type;
+ /* MAC Address of the client. */
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+ /* Init client. */
+ uint8_t client_init;
+ /* Client Index */
+ int8_t client_idx;
+ /* Header length of the client. */
+ uint8_t hdr_len;
+ /* Source pipe of the lan client. */
+ enum ipa_client_type ul_src_pipe;
+};
+
+struct wan_ioctl_per_client_info {
+ /* MAC Address of the client. */
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+ /* Ipv4 UL traffic bytes. */
+ uint64_t ipv4_tx_bytes;
+ /* Ipv4 DL traffic bytes. */
+ uint64_t ipv4_rx_bytes;
+ /* Ipv6 UL traffic bytes. */
+ uint64_t ipv6_tx_bytes;
+ /* Ipv6 DL traffic bytes. */
+ uint64_t ipv6_rx_bytes;
+};
+
+struct wan_ioctl_query_per_client_stats {
+ /* Device type of the client. */
+ enum ipacm_per_client_device_type device_type;
+ /* Indicate whether to reset the stats (use 1) or not */
+ uint8_t reset_stats;
+ /* Indicates whether client is disconnected. */
+ uint8_t disconnect_clnt;
+ /* Number of clients. */
+ uint8_t num_clients;
+ /* Client information. */
+ struct wan_ioctl_per_client_info
+ client_info[IPA_MAX_NUM_HW_PATH_CLIENTS];
+};
+
#define WAN_IOC_ADD_FLT_RULE _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_ADD_FLT_RULE, \
struct ipa_install_fltr_rule_req_msg_v01 *)
@@ -170,4 +227,27 @@ struct wan_ioctl_query_dl_filter_stats {
WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
struct wan_ioctl_query_tether_stats_all *)
+#define WAN_IOC_ADD_UL_FLT_RULE _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_ADD_UL_FLT_RULE, \
+ struct ipa_configure_ul_firewall_rules_req_msg_v01 *)
+
+#define WAN_IOC_ENABLE_PER_CLIENT_STATS _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_ENABLE_PER_CLIENT_STATS, \
+ bool *)
+
+#define WAN_IOC_QUERY_PER_CLIENT_STATS _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_QUERY_PER_CLIENT_STATS, \
+ struct wan_ioctl_query_per_client_stats *)
+
+#define WAN_IOC_SET_LAN_CLIENT_INFO _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_SET_LAN_CLIENT_INFO, \
+ struct wan_ioctl_lan_client_info *)
+
+#define WAN_IOC_SEND_LAN_CLIENT_MSG _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_SEND_LAN_CLIENT_MSG, \
+ struct wan_ioctl_send_lan_client_msg *)
+
+#define WAN_IOC_CLEAR_LAN_CLIENT_INFO _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_CLEAR_LAN_CLIENT_INFO, \
+ struct wan_ioctl_lan_client_info *)
#endif /* _RMNET_IPA_FD_IOCTL_H */