usb: f_gsi: Allow user to specify MAC address for RNDIS/ECM

Currently driver uses random MAC address which gets changed
across composition switches or reboots. Allow user to specify
MAC address using configfs parameter to fix this.

Change-Id: I96710b3419ff7c016b931195a80ce77cd8c9038c
Signed-off-by: Manu Gautam <[email protected]>
This commit is contained in:
Manu Gautam 2018-05-25 12:27:18 +05:30 • committed by Rohith Kollalsi
commit c6585c886a
2 changed files with 101 additions and 10 deletions

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@ -2859,6 +2859,26 @@ static void ipa_ready_callback(void *user_data)
wake_up_interruptible(&gsi->d_port.wait_for_ipa_ready);
}
static void gsi_get_ether_addr(const char *str, u8 *dev_addr)
{
if (str) {
unsigned int i;
for (i = 0; i < ETH_ALEN; i++) {
unsigned char num;
if ((*str == '.') || (*str == ':'))
str++;
num = hex_to_bin(*str++) << 4;
num |= hex_to_bin(*str++);
dev_addr[i] = num;
}
if (is_valid_ether_addr(dev_addr))
return;
}
random_ether_addr(dev_addr);
}
static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
@ -2933,11 +2953,15 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
rndis_set_param_medium(gsi->params, RNDIS_MEDIUM_802_3, 0);
/* export host's Ethernet address in CDC format */
random_ether_addr(gsi->d_port.ipa_init_params.device_ethaddr);
random_ether_addr(gsi->d_port.ipa_init_params.host_ethaddr);
gsi_get_ether_addr(gsi->dev_addr,
gsi->d_port.ipa_init_params.device_ethaddr);
gsi_get_ether_addr(gsi->host_addr,
gsi->d_port.ipa_init_params.host_ethaddr);
log_event_dbg("setting host_ethaddr=%pM, device_ethaddr = %pM",
gsi->d_port.ipa_init_params.host_ethaddr,
gsi->d_port.ipa_init_params.device_ethaddr);
gsi->d_port.ipa_init_params.host_ethaddr,
gsi->d_port.ipa_init_params.device_ethaddr);
memcpy(gsi->ethaddr, &gsi->d_port.ipa_init_params.host_ethaddr,
ETH_ALEN);
rndis_set_host_mac(gsi->params, gsi->ethaddr);
@ -3138,11 +3162,15 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
info.notify_buf_len = GSI_CTRL_NOTIFY_BUFF_LEN;
/* export host's Ethernet address in CDC format */
random_ether_addr(gsi->d_port.ipa_init_params.device_ethaddr);
random_ether_addr(gsi->d_port.ipa_init_params.host_ethaddr);
gsi_get_ether_addr(gsi->dev_addr,
gsi->d_port.ipa_init_params.device_ethaddr);
gsi_get_ether_addr(gsi->host_addr,
gsi->d_port.ipa_init_params.host_ethaddr);
log_event_dbg("setting host_ethaddr=%pM, device_ethaddr = %pM",
gsi->d_port.ipa_init_params.host_ethaddr,
gsi->d_port.ipa_init_params.device_ethaddr);
gsi->d_port.ipa_init_params.host_ethaddr,
gsi->d_port.ipa_init_params.device_ethaddr);
snprintf(gsi->ethaddr, sizeof(gsi->ethaddr),
"%02X%02X%02X%02X%02X%02X",
@ -3578,9 +3606,53 @@ static ssize_t gsi_rndis_class_id_store(struct config_item *item,
}
CONFIGFS_ATTR(gsi_, rndis_class_id);
static ssize_t gsi_host_addr_show(struct config_item *item, char *page)
{
struct f_gsi *gsi = to_gsi_opts(item)->gsi;
return scnprintf(page, PAGE_SIZE, "%s\n", gsi->host_addr);
}
static ssize_t gsi_host_addr_store(struct config_item *item,
const char *page, size_t len)
{
struct f_gsi *gsi = to_gsi_opts(item)->gsi;
if (len > GSI_MAX_MAC_ADDR_LEN)
return -EINVAL;
strlcpy(gsi->host_addr, page, GSI_MAX_MAC_ADDR_LEN);
return len;
}
CONFIGFS_ATTR(gsi_, host_addr);
static ssize_t gsi_dev_addr_show(struct config_item *item, char *page)
{
struct f_gsi *gsi = to_gsi_opts(item)->gsi;
return scnprintf(page, PAGE_SIZE, "%s\n", gsi->dev_addr);
}
static ssize_t gsi_dev_addr_store(struct config_item *item,
const char *page, size_t len)
{
struct f_gsi *gsi = to_gsi_opts(item)->gsi;
if (len > GSI_MAX_MAC_ADDR_LEN)
return -EINVAL;
strlcpy(gsi->dev_addr, page, GSI_MAX_MAC_ADDR_LEN);
return len;
}
CONFIGFS_ATTR(gsi_, dev_addr);
static struct configfs_attribute *gsi_rndis_attrs[] = {
&gsi_attr_info,
&gsi_attr_rndis_class_id,
&gsi_attr_host_addr,
&gsi_attr_dev_addr,
NULL,
};
@ -3590,6 +3662,18 @@ static struct config_item_type gsi_func_rndis_type = {
.ct_owner = THIS_MODULE,
};
static struct configfs_attribute *gsi_ecm_attrs[] = {
&gsi_attr_host_addr,
&gsi_attr_dev_addr,
NULL,
};
static struct config_item_type gsi_func_ecm_type = {
.ct_item_ops = &gsi_item_ops,
.ct_attrs = gsi_ecm_attrs,
.ct_owner = THIS_MODULE,
};
static void gsi_inst_clean(struct gsi_opts *opts)
{
if (opts->gsi->c_port.cdev.dev) {
@ -3642,6 +3726,10 @@ static int gsi_set_inst_name(struct usb_function_instance *fi,
config_group_init_type_name(&opts->func_inst.group,
fi->group.cg_item.ci_name,
&gsi_func_rndis_type);
if (prot_id == IPA_USB_ECM)
config_group_init_type_name(&opts->func_inst.group,
fi->group.cg_item.ci_name,
&gsi_func_ecm_type);
gsi = gsi_function_init(prot_id);
if (IS_ERR(gsi))

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _F_GSI_H
@ -28,6 +28,7 @@
#define GSI_CTRL_NAME_LEN (sizeof(GSI_MBIM_CTRL_NAME)+2)
#define GSI_MAX_CTRL_PKT_SIZE 8192
#define GSI_CTRL_DTR (1 << 0)
#define GSI_MAX_MAC_ADDR_LEN 18
#define GSI_NUM_IN_RNDIS_BUFFERS 50
#define GSI_NUM_IN_RMNET_BUFFERS 50
@ -264,6 +265,8 @@ struct f_gsi {
u32 vendorID;
u8 ethaddr[ETH_ADDR_STR_LEN];
const char *manufacturer;
char host_addr[GSI_MAX_MAC_ADDR_LEN];
char dev_addr[GSI_MAX_MAC_ADDR_LEN];
struct rndis_params *params;
atomic_t connected;
bool data_interface_up;