msm: ipa: Add support for per client lan statistics

Per client lan statistics feature requires fetching data
from IPA-Q6 and share it with user space application.
Make changes to provide ioctl-interface to interact with
IPA Q6 to get the per  client lan statistics.

Change-Id: If0af747cd86058eaa275170f42af1d9e93e81768
Acked-by: Abhishek Choubey <abchoube@qti.qualcomm.com>
Acked-by: Pooja Kumari <kumarip@qti.qualcomm.com>
Acked-by: Chaitanya Pratapa <cpratapa@qti.qualcomm.com>
Signed-off-by: Mohammed Javid <mjavid@codeaurora.org>
Signed-off-by: Utkarsh Saxena <usaxena@codeaurora.org>
This commit is contained in:
Utkarsh Saxena 2017-05-09 15:30:44 +05:30 committed by Mohammed Javid
parent b33f617917
commit c961b0bbfc
11 changed files with 1111 additions and 76 deletions

View file

@ -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[] = {

View file

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

View file

@ -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[] = {

View file

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

View file

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

View file

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

View file

@ -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");

View file

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

View file

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

View file

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

View file

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