staging: usbip: userspace: Memory leak in usbip_exported_device_new
[firefly-linux-kernel-4.4.55.git] / drivers / staging / usbip / userspace / libsrc / usbip_host_driver.c
1 /*
2  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3  *               2005-2007 Takahiro Hirofuchi
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21
22 #include <errno.h>
23 #include <unistd.h>
24
25 #include "usbip_common.h"
26 #include "usbip_host_driver.h"
27
28 #undef  PROGNAME
29 #define PROGNAME "libusbip"
30
31 struct usbip_host_driver *host_driver;
32
33 #define SYSFS_OPEN_RETRIES 100
34
35 static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
36 {
37         char attrpath[SYSFS_PATH_MAX];
38         struct sysfs_attribute *attr;
39         int value = 0;
40         int rc;
41         struct stat s;
42         int retries = SYSFS_OPEN_RETRIES;
43
44         /* This access is racy!
45          *
46          * Just after detach, our driver removes the sysfs
47          * files and recreates them.
48          *
49          * We may try and fail to open the usbip_status of
50          * an exported device in the (short) window where
51          * it has been removed and not yet recreated.
52          *
53          * This is a bug in the interface. Nothing we can do
54          * except work around it here by polling for the sysfs
55          * usbip_status to reappear.
56          */
57
58         snprintf(attrpath, SYSFS_PATH_MAX, "%s/usbip_status",
59                  udev->path);
60
61         while (retries > 0) {
62                 if (stat(attrpath, &s) == 0)
63                         break;
64
65                 if (errno != ENOENT) {
66                         dbg("stat failed: %s", attrpath);
67                         return -1;
68                 }
69
70                 usleep(10000); /* 10ms */
71                 retries--;
72         }
73
74         if (retries == 0)
75                 dbg("usbip_status not ready after %d retries",
76                     SYSFS_OPEN_RETRIES);
77         else if (retries < SYSFS_OPEN_RETRIES)
78                 dbg("warning: usbip_status ready after %d retries",
79                     SYSFS_OPEN_RETRIES - retries);
80
81         attr = sysfs_open_attribute(attrpath);
82         if (!attr) {
83                 dbg("sysfs_open_attribute failed: %s", attrpath);
84                 return -1;
85         }
86
87         rc = sysfs_read_attribute(attr);
88         if (rc) {
89                 dbg("sysfs_read_attribute failed: %s", attrpath);
90                 sysfs_close_attribute(attr);
91                 return -1;
92         }
93
94         value = atoi(attr->value);
95
96         sysfs_close_attribute(attr);
97
98         return value;
99 }
100
101 static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath)
102 {
103         struct usbip_exported_device *edev = NULL;
104         struct usbip_exported_device *edev_old;
105         size_t size;
106         int i;
107
108         edev = calloc(1, sizeof(*edev));
109         if (!edev) {
110                 dbg("calloc failed");
111                 return NULL;
112         }
113
114         edev->sudev = sysfs_open_device_path(sdevpath);
115         if (!edev->sudev) {
116                 dbg("sysfs_open_device_path failed: %s", sdevpath);
117                 goto err;
118         }
119
120         read_usb_device(edev->sudev, &edev->udev);
121
122         edev->status = read_attr_usbip_status(&edev->udev);
123         if (edev->status < 0)
124                 goto err;
125
126         /* reallocate buffer to include usb interface data */
127         size = sizeof(*edev) + edev->udev.bNumInterfaces *
128                 sizeof(struct usbip_usb_interface);
129
130         edev_old = edev;
131         edev = realloc(edev, size);
132         if (!edev) {
133                 edev = edev_old;
134                 dbg("realloc failed");
135                 goto err;
136         }
137
138         for (i = 0; i < edev->udev.bNumInterfaces; i++)
139                 read_usb_interface(&edev->udev, i, &edev->uinf[i]);
140
141         return edev;
142 err:
143         if (edev && edev->sudev)
144                 sysfs_close_device(edev->sudev);
145         if (edev)
146                 free(edev);
147
148         return NULL;
149 }
150
151 static int check_new(struct dlist *dlist, struct sysfs_device *target)
152 {
153         struct sysfs_device *dev;
154
155         dlist_for_each_data(dlist, dev, struct sysfs_device) {
156                 if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE))
157                         /* device found and is not new */
158                         return 0;
159         }
160         return 1;
161 }
162
163 static void delete_nothing(void *unused_data)
164 {
165         /*
166          * NOTE: Do not delete anything, but the container will be deleted.
167          */
168         (void) unused_data;
169 }
170
171 static int refresh_exported_devices(void)
172 {
173         /* sysfs_device of usb_device */
174         struct sysfs_device     *sudev;
175         struct dlist            *sudev_list;
176         struct dlist            *sudev_unique_list;
177         struct usbip_exported_device *edev;
178
179         sudev_unique_list = dlist_new_with_delete(sizeof(struct sysfs_device),
180                                                   delete_nothing);
181
182         sudev_list = sysfs_get_driver_devices(host_driver->sysfs_driver);
183
184         if (!sudev_list) {
185                 /*
186                  * Not an error condition. There are simply no devices bound to
187                  * the driver yet.
188                  */
189                 dbg("bind " USBIP_HOST_DRV_NAME ".ko to a usb device to be "
190                     "exportable!");
191                 return 0;
192         }
193
194         dlist_for_each_data(sudev_list, sudev, struct sysfs_device)
195                 if (check_new(sudev_unique_list, sudev))
196                         dlist_unshift(sudev_unique_list, sudev);
197
198         dlist_for_each_data(sudev_unique_list, sudev, struct sysfs_device) {
199                 edev = usbip_exported_device_new(sudev->path);
200
201                 if (!edev) {
202                         dbg("usbip_exported_device_new failed");
203                         continue;
204                 }
205
206                 dlist_unshift(host_driver->edev_list, edev);
207                 host_driver->ndevs++;
208         }
209
210         dlist_destroy(sudev_unique_list);
211
212         return 0;
213 }
214
215 static struct sysfs_driver *open_sysfs_host_driver(void)
216 {
217         char bus_type[] = "usb";
218         char sysfs_mntpath[SYSFS_PATH_MAX];
219         char host_drv_path[SYSFS_PATH_MAX];
220         struct sysfs_driver *host_drv;
221         int rc;
222
223         rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
224         if (rc < 0) {
225                 dbg("sysfs_get_mnt_path failed");
226                 return NULL;
227         }
228
229         snprintf(host_drv_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s",
230                  sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
231                  USBIP_HOST_DRV_NAME);
232
233         host_drv = sysfs_open_driver_path(host_drv_path);
234         if (!host_drv) {
235                 dbg("sysfs_open_driver_path failed");
236                 return NULL;
237         }
238
239         return host_drv;
240 }
241
242 static void usbip_exported_device_delete(void *dev)
243 {
244         struct usbip_exported_device *edev = dev;
245         sysfs_close_device(edev->sudev);
246         free(dev);
247 }
248
249 int usbip_host_driver_open(void)
250 {
251         int rc;
252
253         host_driver = calloc(1, sizeof(*host_driver));
254         if (!host_driver) {
255                 dbg("calloc failed");
256                 return -1;
257         }
258
259         host_driver->ndevs = 0;
260         host_driver->edev_list =
261                 dlist_new_with_delete(sizeof(struct usbip_exported_device),
262                                       usbip_exported_device_delete);
263         if (!host_driver->edev_list) {
264                 dbg("dlist_new_with_delete failed");
265                 goto err_free_host_driver;
266         }
267
268         host_driver->sysfs_driver = open_sysfs_host_driver();
269         if (!host_driver->sysfs_driver)
270                 goto err_destroy_edev_list;
271
272         rc = refresh_exported_devices();
273         if (rc < 0)
274                 goto err_close_sysfs_driver;
275
276         return 0;
277
278 err_close_sysfs_driver:
279         sysfs_close_driver(host_driver->sysfs_driver);
280 err_destroy_edev_list:
281         dlist_destroy(host_driver->edev_list);
282 err_free_host_driver:
283         free(host_driver);
284         host_driver = NULL;
285
286         return -1;
287 }
288
289 void usbip_host_driver_close(void)
290 {
291         if (!host_driver)
292                 return;
293
294         if (host_driver->edev_list)
295                 dlist_destroy(host_driver->edev_list);
296         if (host_driver->sysfs_driver)
297                 sysfs_close_driver(host_driver->sysfs_driver);
298
299         free(host_driver);
300         host_driver = NULL;
301 }
302
303 int usbip_host_refresh_device_list(void)
304 {
305         int rc;
306
307         if (host_driver->edev_list)
308                 dlist_destroy(host_driver->edev_list);
309
310         host_driver->ndevs = 0;
311         host_driver->edev_list =
312                 dlist_new_with_delete(sizeof(struct usbip_exported_device),
313                                       usbip_exported_device_delete);
314         if (!host_driver->edev_list) {
315                 dbg("dlist_new_with_delete failed");
316                 return -1;
317         }
318
319         rc = refresh_exported_devices();
320         if (rc < 0)
321                 return -1;
322
323         return 0;
324 }
325
326 int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
327 {
328         char attr_name[] = "usbip_sockfd";
329         char attr_path[SYSFS_PATH_MAX];
330         struct sysfs_attribute *attr;
331         char sockfd_buff[30];
332         int ret;
333
334         if (edev->status != SDEV_ST_AVAILABLE) {
335                 dbg("device not available: %s", edev->udev.busid);
336                 switch (edev->status) {
337                 case SDEV_ST_ERROR:
338                         dbg("status SDEV_ST_ERROR");
339                         break;
340                 case SDEV_ST_USED:
341                         dbg("status SDEV_ST_USED");
342                         break;
343                 default:
344                         dbg("status unknown: 0x%x", edev->status);
345                 }
346                 return -1;
347         }
348
349         /* only the first interface is true */
350         snprintf(attr_path, sizeof(attr_path), "%s/%s",
351                  edev->udev.path, attr_name);
352
353         attr = sysfs_open_attribute(attr_path);
354         if (!attr) {
355                 dbg("sysfs_open_attribute failed: %s", attr_path);
356                 return -1;
357         }
358
359         snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
360         dbg("write: %s", sockfd_buff);
361
362         ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff));
363         if (ret < 0) {
364                 dbg("sysfs_write_attribute failed: sockfd %s to %s",
365                     sockfd_buff, attr_path);
366                 goto err_write_sockfd;
367         }
368
369         dbg("connect: %s", edev->udev.busid);
370
371 err_write_sockfd:
372         sysfs_close_attribute(attr);
373
374         return ret;
375 }
376
377 struct usbip_exported_device *usbip_host_get_device(int num)
378 {
379         struct usbip_exported_device *edev;
380         struct dlist *dlist = host_driver->edev_list;
381         int cnt = 0;
382
383         dlist_for_each_data(dlist, edev, struct usbip_exported_device) {
384                 if (num == cnt)
385                         return edev;
386                 else
387                         cnt++;
388         }
389
390         return NULL;
391 }