usb: gadget: rndis: remove the limit of available rndis connections

RNDIS function has a limitation on the number of allowed instances.
So far it has been RNDIS_MAX_CONFIGS, which happens to be one.
In order to eliminate this kind of arbitrary limitation we should not
preallocate a predefined (RNDIS_MAX_CONFIGS) array of struct rndis_params
instances but instead allow allocating them on demand.

This patch allocates struct rndis_params on demand in rndis_register().
Coversly, the structure is free()'d in rndis_deregister().
If CONFIG_USB_GADGET_DEBUG_FILES is set, the proc files are created which
is the same behaviour as before, but the moment of creation is delayed
until struct rndis_params is actually allocated.

rnids_init() and rndis_exit() have nothing to do, so they are eliminated.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Andrzej Pietrasiewicz 2015-02-06 13:43:30 +01:00 committed by Felipe Balbi
parent 6122b151c7
commit d6d22922d9
4 changed files with 78 additions and 88 deletions

View file

@ -526,8 +526,6 @@ Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0. which was assigned by the net core, e. g. usb0.
By default there can be only 1 RNDIS interface in the system.
Testing the RNDIS function Testing the RNDIS function
-------------------------- --------------------------

View file

@ -1012,26 +1012,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
return &rndis->port.func; return &rndis->port.func;
} }
DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc); DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
static int __init rndis_mod_init(void)
{
int ret;
ret = rndis_init();
if (ret)
return ret;
return usb_function_register(&rndisusb_func);
}
module_init(rndis_mod_init);
static void __exit rndis_mod_exit(void)
{
usb_function_unregister(&rndisusb_func);
rndis_exit();
}
module_exit(rndis_mod_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell"); MODULE_AUTHOR("David Brownell");

View file

@ -25,6 +25,7 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/idr.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -57,10 +58,13 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
#define rndis_debug 0 #define rndis_debug 0
#endif #endif
#define RNDIS_MAX_CONFIGS 1 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
#define NAME_TEMPLATE "driver/rndis-%03d"
static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS]; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
static DEFINE_IDA(rndis_ida);
/* Driver Version */ /* Driver Version */
static const __le32 rndis_driver_version = cpu_to_le32(1); static const __le32 rndis_driver_version = cpu_to_le32(1);
@ -69,6 +73,11 @@ static const __le32 rndis_driver_version = cpu_to_le32(1);
static rndis_resp_t *rndis_add_response(struct rndis_params *params, static rndis_resp_t *rndis_add_response(struct rndis_params *params,
u32 length); u32 length);
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
static const struct file_operations rndis_proc_fops;
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
/* supported OIDs */ /* supported OIDs */
static const u32 oid_supported_list[] = static const u32 oid_supported_list[] =
@ -850,38 +859,93 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf)
} }
EXPORT_SYMBOL_GPL(rndis_msg_parser); EXPORT_SYMBOL_GPL(rndis_msg_parser);
static inline int rndis_get_nr(void)
{
return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL);
}
static inline void rndis_put_nr(int nr)
{
ida_simple_remove(&rndis_ida, nr);
}
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v) struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
{ {
struct rndis_params *params;
u8 i; u8 i;
if (!resp_avail) if (!resp_avail)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { i = rndis_get_nr();
if (!rndis_per_dev_params[i].used) { if (i < 0) {
rndis_per_dev_params[i].used = 1; pr_debug("failed\n");
rndis_per_dev_params[i].resp_avail = resp_avail;
rndis_per_dev_params[i].v = v; return ERR_PTR(-ENODEV);
pr_debug("%s: configNr = %d\n", __func__, i); }
return &rndis_per_dev_params[i];
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params) {
rndis_put_nr(i);
return ERR_PTR(-ENOMEM);
}
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
{
struct proc_dir_entry *proc_entry;
char name[20];
sprintf(name, NAME_TEMPLATE, i);
proc_entry = proc_create_data(name, 0660, NULL,
&rndis_proc_fops, params);
if (!proc_entry) {
kfree(params);
rndis_put_nr(i);
return ERR_PTR(-EIO);
} }
} }
pr_debug("failed\n"); #endif
return ERR_PTR(-ENODEV); params->confignr = i;
params->used = 1;
params->state = RNDIS_UNINITIALIZED;
params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
params->resp_avail = resp_avail;
params->v = v;
INIT_LIST_HEAD(&(params->resp_queue));
pr_debug("%s: configNr = %d\n", __func__, i);
return params;
} }
EXPORT_SYMBOL_GPL(rndis_register); EXPORT_SYMBOL_GPL(rndis_register);
void rndis_deregister(struct rndis_params *params) void rndis_deregister(struct rndis_params *params)
{ {
u8 i;
pr_debug("%s:\n", __func__); pr_debug("%s:\n", __func__);
if (!params) if (!params)
return; return;
params->used = 0;
i = params->confignr;
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
{
u8 i;
char name[20];
sprintf(name, NAME_TEMPLATE, i);
remove_proc_entry(name, NULL);
}
#endif
kfree(params);
rndis_put_nr(i);
} }
EXPORT_SYMBOL_GPL(rndis_deregister); EXPORT_SYMBOL_GPL(rndis_deregister);
int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev, int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
u16 *cdc_filter) u16 *cdc_filter)
{ {
@ -1114,54 +1178,4 @@ static const struct file_operations rndis_proc_fops = {
#define NAME_TEMPLATE "driver/rndis-%03d" #define NAME_TEMPLATE "driver/rndis-%03d"
static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
int rndis_init(void)
{
u8 i;
for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
char name [20];
sprintf(name, NAME_TEMPLATE, i);
rndis_connect_state[i] = proc_create_data(name, 0660, NULL,
&rndis_proc_fops,
(void *)(rndis_per_dev_params + i));
if (!rndis_connect_state[i]) {
pr_debug("%s: remove entries", __func__);
while (i) {
sprintf(name, NAME_TEMPLATE, --i);
remove_proc_entry(name, NULL);
}
pr_debug("\n");
return -EIO;
}
#endif
rndis_per_dev_params[i].confignr = i;
rndis_per_dev_params[i].used = 0;
rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
rndis_per_dev_params[i].media_state
= RNDIS_MEDIA_STATE_DISCONNECTED;
INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
}
return 0;
}
void rndis_exit(void)
{
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
u8 i;
char name[20];
for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
sprintf(name, NAME_TEMPLATE, i);
remove_proc_entry(name, NULL);
}
#endif
}

View file

@ -39,8 +39,6 @@ struct f_rndis_opts {
int refcnt; int refcnt;
}; };
int rndis_init(void);
void rndis_exit(void);
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
#endif /* U_RNDIS_H */ #endif /* U_RNDIS_H */