From c6585c886adce018d61f91611dd6001a69d25dad Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Fri, 25 May 2018 12:27:18 +0530 Subject: [PATCH] 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 --- drivers/usb/gadget/function/f_gsi.c | 106 +++++++++++++++++++++++++--- drivers/usb/gadget/function/f_gsi.h | 5 +- 2 files changed, 101 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index cd6f8f1c7017..d06ff00f6565 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -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 @@ -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)) diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 11de421a6e18..da88e00b0b53 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -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;