msm: ipa: Add new IOCTLs to get and set MTU

Add a new IOCTL that will allow userspace modules to
get and set the v4/v6 mtu for a specific rmnet interface
for IPA driver and IPACM to use.

Change-Id: Iaf0685ef7095960ddd1cd3fff803956a18e0a942
Signed-off-by: Chaitanya Pratapa <cpratapa@codeaurora.org>
Signed-off-by: Michael Adisumarta <madisuma@codeaurora.org>
This commit is contained in:
Chaitanya Pratapa 2020-10-17 07:14:46 -07:00 • committed by Michael Adisumarta
commit 7abd8fd060
4 changed files with 241 additions and 0 deletions

View file

@ -75,6 +75,7 @@ const char *ipa3_event_name[IPA_EVENT_MAX_NUM] = {
__stringify(IPA_GSB_DISCONNECT),
__stringify(IPA_COALESCE_ENABLE),
__stringify(IPA_COALESCE_DISABLE),
__stringify(IPA_SET_MTU),
__stringify_1(WIGIG_CLIENT_CONNECT),
__stringify_1(WIGIG_FST_SWITCH),
};

View file

@ -121,6 +121,8 @@ struct ipa3_rmnet_mux_val {
bool ul_flt_reg;
bool mux_hdr_set;
uint32_t hdr_hdl;
uint16_t mtu_v4;
uint16_t mtu_v6;
};
extern struct qmi_elem_info
@ -305,6 +307,9 @@ 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 rmnet_ipa3_get_wan_mtu(
struct ipa_mtu_info *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);

View file

@ -90,6 +90,10 @@ static DECLARE_DELAYED_WORK(ipa_tether_stats_poll_wakequeue_work,
static int rmnet_ipa_send_coalesce_notification(uint8_t qmap_id, bool enable,
bool tcp, bool udp);
static int rmnet_ipa_send_set_mtu_notification(char *if_name,
uint16_t mtu_v4, uint16_t mtu_v6, enum ipa_ip_type ip);
enum ipa3_wwan_device_status {
WWAN_DEVICE_INACTIVE = 0,
WWAN_DEVICE_ACTIVE = 1
@ -1756,6 +1760,8 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct mutex *mux_mutex_ptr;
int wan_ep;
bool tcp_en = false, udp_en = false;
bool mtu_v4_set = false, mtu_v6_set = false;
enum ipa_ip_type iptype;
IPAWANDBG("rmnet_ipa got ioctl number 0x%08x", cmd);
switch (cmd) {
@ -2086,6 +2092,65 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
mutex_unlock(&rmnet_ipa3_ctx->clock_vote.mutex);
break;
/* Get MTU */
case RMNET_IOCTL_GET_MTU:
mux_channel = rmnet_ipa3_ctx->mux_channel;
rmnet_index =
find_vchannel_name_index(ext_ioctl_data.u.mtu_params.if_name);
if (rmnet_index == MAX_NUM_OF_MUX_CHANNEL) {
IPAWANERR("%s is an invalid iface name\n",
ext_ioctl_data.u.mtu_params.if_name);
return -ENODEV;
}
IPAWANDBG("getting v4 MTU = %d\n", mux_channel[rmnet_index].mtu_v4);
ext_ioctl_data.u.mtu_params.mtu_v4 =
mux_channel[rmnet_index].mtu_v4;
IPAWANDBG("getting v6 MTU = %d\n", mux_channel[rmnet_index].mtu_v6);
ext_ioctl_data.u.mtu_params.mtu_v6 =
mux_channel[rmnet_index].mtu_v6;
break;
/* Set MTU */
case RMNET_IOCTL_SET_MTU:
mux_channel = rmnet_ipa3_ctx->mux_channel;
rmnet_index =
find_vchannel_name_index(ext_ioctl_data.u.mtu_params.if_name);
if (rmnet_index == MAX_NUM_OF_MUX_CHANNEL) {
IPAWANERR("%s is an invalid iface name\n",
ext_ioctl_data.u.mtu_params.if_name);
return -ENODEV;
}
/* V4 case */
if (ext_ioctl_data.u.mtu_params.mtu_v4 > 0) {
mux_channel[rmnet_index].mtu_v4 =
ext_ioctl_data.u.mtu_params.mtu_v4;
mtu_v4_set = true;
IPAWANDBG("Set v4 MTU = %d\n", mux_channel[rmnet_index].mtu_v4);
iptype = IPA_IP_v4;
}
/* V6 case */
if (ext_ioctl_data.u.mtu_params.mtu_v6 > 0) {
mux_channel[rmnet_index].mtu_v6 =
ext_ioctl_data.u.mtu_params.mtu_v6;
mtu_v6_set = true;
IPAWANDBG("Set v6 MTU = %d\n", mux_channel[rmnet_index].mtu_v6);
iptype = IPA_IP_v6;
}
if (mtu_v4_set && mtu_v6_set)
iptype = IPA_IP_MAX;
rc = rmnet_ipa_send_set_mtu_notification(
ext_ioctl_data.u.mtu_params.if_name,
mux_channel[rmnet_index].mtu_v4,
mux_channel[rmnet_index].mtu_v6,
iptype);
break;
default:
IPAWANERR("[%s] unsupported extended cmd[%d]",
dev->name,
@ -2179,6 +2244,37 @@ static int rmnet_ipa_send_coalesce_notification(uint8_t qmap_id,
return 0;
}
static int rmnet_ipa_send_set_mtu_notification(char *if_name,
uint16_t mtu_v4, uint16_t mtu_v6, enum ipa_ip_type ip)
{
struct ipa_msg_meta msg_meta;
struct ipa_mtu_info *mtu_info;
int rc;
memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
mtu_info = kzalloc(sizeof(*mtu_info), GFP_KERNEL);
if (!mtu_info)
return -ENOMEM;
strlcpy(mtu_info->if_name, if_name, IPA_RESOURCE_NAME_MAX);
mtu_info->mtu_v4 = mtu_v4;
mtu_info->mtu_v6 = mtu_v6;
mtu_info->ip_type = ip;
msg_meta.msg_type = IPA_SET_MTU;
msg_meta.msg_len = sizeof(struct ipa_mtu_info);
rc = ipa_send_msg(&msg_meta, mtu_info, ipa3_wwan_msg_free_cb);
if (rc) {
IPAWANERR("ipa_send_msg failed: %d\n", rc);
return -EFAULT;
}
IPAWANDBG(
"sent new mtu_v4(%d)/mtu_v6(%d) with iptype(%d) for iface(%s) to IPACM",
mtu_v4, mtu_v6, ip, if_name);
return 0;
}
int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state)
{
uint32_t bw_mbps = 0;
@ -4785,13 +4881,118 @@ int rmnet_ipa3_query_per_client_stats(
return 0;
}
/* rmnet_ipa3_get_wan_mtu() -
* @data - IOCTL data
*
* This function handles WAN_IOC_GET_WAN_MTU.
* It is used to send WAN MTU information to IPACM.
*
* Return codes:
* 0: Success
* -EINVAL: Invalid args provided
*/
int rmnet_ipa3_get_wan_mtu(
struct ipa_mtu_info *data)
{
struct ipa3_rmnet_mux_val *mux_channel;
int rmnet_index;
mux_channel = rmnet_ipa3_ctx->mux_channel;
rmnet_index =
find_vchannel_name_index(data->if_name);
if (rmnet_index == MAX_NUM_OF_MUX_CHANNEL) {
IPAWANERR("%s is an invalid iface name\n",
data->if_name);
return -ENODEV;
}
IPAWANDBG("getting v4 MTU = %d\n", mux_channel[rmnet_index].mtu_v4);
data->mtu_v4 =
mux_channel[rmnet_index].mtu_v4;
IPAWANDBG("getting v6 MTU = %d\n", mux_channel[rmnet_index].mtu_v6);
data->mtu_v6 =
mux_channel[rmnet_index].mtu_v6;
return 0;
}
#ifdef CONFIG_DEBUG_FS
static char dbg_buff[4096];
static ssize_t rmnet_ipa_set_mtu(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
__s8 if_name[IFNAMSIZ];
uint16_t mtu_v4 = 0, mtu_v6 = 0;
unsigned long missing;
char *sptr, *token;
if (count >= sizeof(dbg_buff))
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, count);
if (missing)
return -EFAULT;
dbg_buff[count] = '\0';
sptr = dbg_buff;
memset(if_name, 0, IFNAMSIZ);
token = strsep(&sptr, " ");
if (!token)
return -EINVAL;
strlcpy(if_name, token, IFNAMSIZ);
token = strsep(&sptr, " ");
if (!token)
return -EINVAL;
if (kstrtou16(token, 0, &mtu_v4))
return -EINVAL;
token = strsep(&sptr, " ");
if (!token)
return -EINVAL;
if (kstrtou16(token, 0, &mtu_v6))
return -EINVAL;
rmnet_ipa_send_set_mtu_notification(
if_name,
mtu_v4,
mtu_v6, IPA_IP_MAX);
return count;
}
#define RMNET_IPA_WRITE_ONLY_MODE 0220
struct rmnet_ipa_debugfs_file {
const char *name;
umode_t mode;
void *data;
const struct file_operations fops;
};
static const struct rmnet_ipa_debugfs_file debugfs_files[] = {
{
"mtu", RMNET_IPA_WRITE_ONLY_MODE, NULL, {
.write = rmnet_ipa_set_mtu,
}
},
};
static void rmnet_ipa_debugfs_init(void)
{
const mode_t read_write_mode = 0664;
int i = 0;
struct dentry *file;
struct rmnet_ipa_debugfs *dbgfs = &rmnet_ipa3_ctx->dbgfs;
const size_t debugfs_files_num =
sizeof(debugfs_files) / sizeof(struct rmnet_ipa_debugfs_file);
dbgfs->dent = debugfs_create_dir("rmnet_ipa", 0);
@ -4800,6 +5001,18 @@ static void rmnet_ipa_debugfs_init(void)
return;
}
for (i = 0; i < debugfs_files_num; ++i) {
const struct rmnet_ipa_debugfs_file *curr = &debugfs_files[i];
file = debugfs_create_file(curr->name, curr->mode, dbgfs->dent,
curr->data, &curr->fops);
if (!file || IS_ERR(file)) {
IPAERR("fail to create file for debug_fs %s\n",
curr->name);
goto fail;
}
}
dbgfs->dfile_outstanding_high = debugfs_create_u32("outstanding_high",
read_write_mode, dbgfs->dent,
&rmnet_ipa3_ctx->outstanding_high);

View file

@ -475,6 +475,28 @@ static long ipa3_wan_ioctl(struct file *filp,
}
break;
case WAN_IOC_GET_WAN_MTU:
IPAWANDBG_LOW("got WAN_IOC_GET_WAN_MTU :>>>\n");
pyld_sz = sizeof(struct ipa_mtu_info);
param = memdup_user((const void __user *)arg, pyld_sz);
if (IS_ERR(param)) {
retval = PTR_ERR(param);
break;
}
if (rmnet_ipa3_get_wan_mtu(
(struct ipa_mtu_info *)
param)) {
IPAWANERR("WAN_IOC_GET_WAN_MTU failed\n");
retval = -EFAULT;
break;
}
if (copy_to_user((void __user *)arg, param, pyld_sz)) {
retval = -EFAULT;
break;
}
break;
default:
retval = -ENOTTY;
}