Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andrzej Pietrasiewicz and committed by
Felipe Balbi
d6d22922 6122b151

+78 -88
-2
Documentation/usb/gadget-testing.txt
··· 526 526 configuration. The ifname is read-only and contains the name of the interface 527 527 which was assigned by the net core, e. g. usb0. 528 528 529 - By default there can be only 1 RNDIS interface in the system. 530 - 531 529 Testing the RNDIS function 532 530 -------------------------- 533 531
+1 -21
drivers/usb/gadget/function/f_rndis.c
··· 1012 1012 return &rndis->port.func; 1013 1013 } 1014 1014 1015 - DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc); 1016 - 1017 - static int __init rndis_mod_init(void) 1018 - { 1019 - int ret; 1020 - 1021 - ret = rndis_init(); 1022 - if (ret) 1023 - return ret; 1024 - 1025 - return usb_function_register(&rndisusb_func); 1026 - } 1027 - module_init(rndis_mod_init); 1028 - 1029 - static void __exit rndis_mod_exit(void) 1030 - { 1031 - usb_function_unregister(&rndisusb_func); 1032 - rndis_exit(); 1033 - } 1034 - module_exit(rndis_mod_exit); 1035 - 1015 + DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc); 1036 1016 MODULE_LICENSE("GPL"); 1037 1017 MODULE_AUTHOR("David Brownell");
+77 -63
drivers/usb/gadget/function/rndis.c
··· 25 25 #include <linux/moduleparam.h> 26 26 #include <linux/kernel.h> 27 27 #include <linux/errno.h> 28 + #include <linux/idr.h> 28 29 #include <linux/list.h> 29 30 #include <linux/proc_fs.h> 30 31 #include <linux/slab.h> ··· 58 57 #define rndis_debug 0 59 58 #endif 60 59 61 - #define RNDIS_MAX_CONFIGS 1 60 + #ifdef CONFIG_USB_GADGET_DEBUG_FILES 62 61 62 + #define NAME_TEMPLATE "driver/rndis-%03d" 63 63 64 - static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS]; 64 + #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ 65 + 66 + static DEFINE_IDA(rndis_ida); 65 67 66 68 /* Driver Version */ 67 69 static const __le32 rndis_driver_version = cpu_to_le32(1); ··· 73 69 static rndis_resp_t *rndis_add_response(struct rndis_params *params, 74 70 u32 length); 75 71 72 + #ifdef CONFIG_USB_GADGET_DEBUG_FILES 73 + 74 + static const struct file_operations rndis_proc_fops; 75 + 76 + #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ 76 77 77 78 /* supported OIDs */ 78 79 static const u32 oid_supported_list[] = ··· 859 850 } 860 851 EXPORT_SYMBOL_GPL(rndis_msg_parser); 861 852 853 + static inline int rndis_get_nr(void) 854 + { 855 + return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL); 856 + } 857 + 858 + static inline void rndis_put_nr(int nr) 859 + { 860 + ida_simple_remove(&rndis_ida, nr); 861 + } 862 + 862 863 struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v) 863 864 { 865 + struct rndis_params *params; 864 866 u8 i; 865 867 866 868 if (!resp_avail) 867 869 return ERR_PTR(-EINVAL); 868 870 869 - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { 870 - if (!rndis_per_dev_params[i].used) { 871 - rndis_per_dev_params[i].used = 1; 872 - rndis_per_dev_params[i].resp_avail = resp_avail; 873 - rndis_per_dev_params[i].v = v; 874 - pr_debug("%s: configNr = %d\n", __func__, i); 875 - return &rndis_per_dev_params[i]; 871 + i = rndis_get_nr(); 872 + if (i < 0) { 873 + pr_debug("failed\n"); 874 + 875 + return ERR_PTR(-ENODEV); 876 + } 877 + 878 + params = kzalloc(sizeof(*params), GFP_KERNEL); 879 + if (!params) { 880 + rndis_put_nr(i); 881 + 882 + return ERR_PTR(-ENOMEM); 883 + } 884 + 885 + #ifdef CONFIG_USB_GADGET_DEBUG_FILES 886 + { 887 + struct proc_dir_entry *proc_entry; 888 + char name[20]; 889 + 890 + sprintf(name, NAME_TEMPLATE, i); 891 + proc_entry = proc_create_data(name, 0660, NULL, 892 + &rndis_proc_fops, params); 893 + if (!proc_entry) { 894 + kfree(params); 895 + rndis_put_nr(i); 896 + 897 + return ERR_PTR(-EIO); 876 898 } 877 899 } 878 - pr_debug("failed\n"); 900 + #endif 879 901 880 - return ERR_PTR(-ENODEV); 902 + params->confignr = i; 903 + params->used = 1; 904 + params->state = RNDIS_UNINITIALIZED; 905 + params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED; 906 + params->resp_avail = resp_avail; 907 + params->v = v; 908 + INIT_LIST_HEAD(&(params->resp_queue)); 909 + pr_debug("%s: configNr = %d\n", __func__, i); 910 + 911 + return params; 881 912 } 882 913 EXPORT_SYMBOL_GPL(rndis_register); 883 914 884 915 void rndis_deregister(struct rndis_params *params) 885 916 { 917 + u8 i; 918 + 886 919 pr_debug("%s:\n", __func__); 887 920 888 921 if (!params) 889 922 return; 890 - params->used = 0; 923 + 924 + i = params->confignr; 925 + 926 + #ifdef CONFIG_USB_GADGET_DEBUG_FILES 927 + { 928 + u8 i; 929 + char name[20]; 930 + 931 + sprintf(name, NAME_TEMPLATE, i); 932 + remove_proc_entry(name, NULL); 933 + } 934 + #endif 935 + 936 + kfree(params); 937 + rndis_put_nr(i); 891 938 } 892 939 EXPORT_SYMBOL_GPL(rndis_deregister); 893 - 894 940 int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev, 895 941 u16 *cdc_filter) 896 942 { ··· 1178 1114 1179 1115 #define NAME_TEMPLATE "driver/rndis-%03d" 1180 1116 1181 - static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; 1182 - 1183 1117 #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ 1184 - 1185 - 1186 - int rndis_init(void) 1187 - { 1188 - u8 i; 1189 - 1190 - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { 1191 - #ifdef CONFIG_USB_GADGET_DEBUG_FILES 1192 - char name [20]; 1193 - 1194 - sprintf(name, NAME_TEMPLATE, i); 1195 - rndis_connect_state[i] = proc_create_data(name, 0660, NULL, 1196 - &rndis_proc_fops, 1197 - (void *)(rndis_per_dev_params + i)); 1198 - if (!rndis_connect_state[i]) { 1199 - pr_debug("%s: remove entries", __func__); 1200 - while (i) { 1201 - sprintf(name, NAME_TEMPLATE, --i); 1202 - remove_proc_entry(name, NULL); 1203 - } 1204 - pr_debug("\n"); 1205 - return -EIO; 1206 - } 1207 - #endif 1208 - rndis_per_dev_params[i].confignr = i; 1209 - rndis_per_dev_params[i].used = 0; 1210 - rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED; 1211 - rndis_per_dev_params[i].media_state 1212 - = RNDIS_MEDIA_STATE_DISCONNECTED; 1213 - INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); 1214 - } 1215 - 1216 - return 0; 1217 - } 1218 - 1219 - void rndis_exit(void) 1220 - { 1221 - #ifdef CONFIG_USB_GADGET_DEBUG_FILES 1222 - u8 i; 1223 - char name[20]; 1224 - 1225 - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { 1226 - sprintf(name, NAME_TEMPLATE, i); 1227 - remove_proc_entry(name, NULL); 1228 - } 1229 - #endif 1230 - } 1231 -
-2
drivers/usb/gadget/function/u_rndis.h
··· 39 39 int refcnt; 40 40 }; 41 41 42 - int rndis_init(void); 43 - void rndis_exit(void); 44 42 void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); 45 43 46 44 #endif /* U_RNDIS_H */