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 @@ -127,6 +127,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) */ @@ -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) /** @@ -1060,6 +1078,48 @@ struct ipa_rt_rule_del { int status; }; +/** + * 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) @@ -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 */